1133fac0eSSudarsana Kalluru /* QLogic qede NIC Driver
2e8f1cb50SMintz, Yuval  * Copyright (c) 2015-2017  QLogic Corporation
3133fac0eSSudarsana Kalluru  *
4e8f1cb50SMintz, Yuval  * This software is available to you under a choice of one of two
5e8f1cb50SMintz, Yuval  * licenses.  You may choose to be licensed under the terms of the GNU
6e8f1cb50SMintz, Yuval  * General Public License (GPL) Version 2, available from the file
7e8f1cb50SMintz, Yuval  * COPYING in the main directory of this source tree, or the
8e8f1cb50SMintz, Yuval  * OpenIB.org BSD license below:
9e8f1cb50SMintz, Yuval  *
10e8f1cb50SMintz, Yuval  *     Redistribution and use in source and binary forms, with or
11e8f1cb50SMintz, Yuval  *     without modification, are permitted provided that the following
12e8f1cb50SMintz, Yuval  *     conditions are met:
13e8f1cb50SMintz, Yuval  *
14e8f1cb50SMintz, Yuval  *      - Redistributions of source code must retain the above
15e8f1cb50SMintz, Yuval  *        copyright notice, this list of conditions and the following
16e8f1cb50SMintz, Yuval  *        disclaimer.
17e8f1cb50SMintz, Yuval  *
18e8f1cb50SMintz, Yuval  *      - Redistributions in binary form must reproduce the above
19e8f1cb50SMintz, Yuval  *        copyright notice, this list of conditions and the following
20e8f1cb50SMintz, Yuval  *        disclaimer in the documentation and /or other materials
21e8f1cb50SMintz, Yuval  *        provided with the distribution.
22e8f1cb50SMintz, Yuval  *
23e8f1cb50SMintz, Yuval  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24e8f1cb50SMintz, Yuval  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25e8f1cb50SMintz, Yuval  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26e8f1cb50SMintz, Yuval  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27e8f1cb50SMintz, Yuval  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28e8f1cb50SMintz, Yuval  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29e8f1cb50SMintz, Yuval  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30e8f1cb50SMintz, Yuval  * SOFTWARE.
31133fac0eSSudarsana Kalluru  */
32133fac0eSSudarsana Kalluru #include <linux/version.h>
33133fac0eSSudarsana Kalluru #include <linux/types.h>
34133fac0eSSudarsana Kalluru #include <linux/netdevice.h>
3516f46bf0SSudarsana Reddy Kalluru #include <linux/etherdevice.h>
36133fac0eSSudarsana Kalluru #include <linux/ethtool.h>
37133fac0eSSudarsana Kalluru #include <linux/string.h>
38133fac0eSSudarsana Kalluru #include <linux/pci.h>
39133fac0eSSudarsana Kalluru #include <linux/capability.h>
40f29ffdb6SMintz, Yuval #include <linux/vmalloc.h>
41133fac0eSSudarsana Kalluru #include "qede.h"
424c55215cSSudarsana Reddy Kalluru #include "qede_ptp.h"
43133fac0eSSudarsana Kalluru 
44133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_OFFSET(stat_name) \
45133fac0eSSudarsana Kalluru 	 (offsetof(struct qede_rx_queue, stat_name))
46133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_STRING(stat_name) (#stat_name)
47133fac0eSSudarsana Kalluru #define QEDE_RQSTAT(stat_name) \
48133fac0eSSudarsana Kalluru 	 {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)}
4916f46bf0SSudarsana Reddy Kalluru 
5016f46bf0SSudarsana Reddy Kalluru #define QEDE_SELFTEST_POLL_COUNT 100
5116f46bf0SSudarsana Reddy Kalluru 
52133fac0eSSudarsana Kalluru static const struct {
53133fac0eSSudarsana Kalluru 	u64 offset;
54133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
55133fac0eSSudarsana Kalluru } qede_rqstats_arr[] = {
5668db9ec2SSudarsana Reddy Kalluru 	QEDE_RQSTAT(rcv_pkts),
57133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_hw_errors),
58133fac0eSSudarsana Kalluru 	QEDE_RQSTAT(rx_alloc_errors),
59c72a6125SManish Chopra 	QEDE_RQSTAT(rx_ip_frags),
60496e0517SMintz, Yuval 	QEDE_RQSTAT(xdp_no_pass),
61133fac0eSSudarsana Kalluru };
62133fac0eSSudarsana Kalluru 
63133fac0eSSudarsana Kalluru #define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr)
6468db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_OFFSET(stat_name) \
6568db9ec2SSudarsana Reddy Kalluru 	(offsetof(struct qede_tx_queue, stat_name))
6668db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT_STRING(stat_name) (#stat_name)
6768db9ec2SSudarsana Reddy Kalluru #define QEDE_TQSTAT(stat_name) \
6868db9ec2SSudarsana Reddy Kalluru 	{QEDE_TQSTAT_OFFSET(stat_name), QEDE_TQSTAT_STRING(stat_name)}
6968db9ec2SSudarsana Reddy Kalluru #define QEDE_NUM_TQSTATS ARRAY_SIZE(qede_tqstats_arr)
7068db9ec2SSudarsana Reddy Kalluru static const struct {
7168db9ec2SSudarsana Reddy Kalluru 	u64 offset;
7268db9ec2SSudarsana Reddy Kalluru 	char string[ETH_GSTRING_LEN];
7368db9ec2SSudarsana Reddy Kalluru } qede_tqstats_arr[] = {
7468db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(xmit_pkts),
7568db9ec2SSudarsana Reddy Kalluru 	QEDE_TQSTAT(stopped_cnt),
7668db9ec2SSudarsana Reddy Kalluru };
7768db9ec2SSudarsana Reddy Kalluru 
789c79ddaaSMintz, Yuval #define QEDE_STAT_OFFSET(stat_name, type, base) \
799c79ddaaSMintz, Yuval 	(offsetof(type, stat_name) + (base))
804dbcd640SMintz, Yuval #define QEDE_STAT_STRING(stat_name)	(#stat_name)
819c79ddaaSMintz, Yuval #define _QEDE_STAT(stat_name, type, base, attr) \
829c79ddaaSMintz, Yuval 	{QEDE_STAT_OFFSET(stat_name, type, base), \
839c79ddaaSMintz, Yuval 	 QEDE_STAT_STRING(stat_name), \
849c79ddaaSMintz, Yuval 	 attr}
859c79ddaaSMintz, Yuval #define QEDE_STAT(stat_name) \
869c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_common, 0, 0x0)
879c79ddaaSMintz, Yuval #define QEDE_PF_STAT(stat_name) \
889c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_common, 0, \
899c79ddaaSMintz, Yuval 		   BIT(QEDE_STAT_PF_ONLY))
909c79ddaaSMintz, Yuval #define QEDE_PF_BB_STAT(stat_name) \
919c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_bb, \
929c79ddaaSMintz, Yuval 		   offsetof(struct qede_stats, bb), \
939c79ddaaSMintz, Yuval 		   BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_BB_ONLY))
949c79ddaaSMintz, Yuval #define QEDE_PF_AH_STAT(stat_name) \
959c79ddaaSMintz, Yuval 	_QEDE_STAT(stat_name, struct qede_stats_ah, \
969c79ddaaSMintz, Yuval 		   offsetof(struct qede_stats, ah), \
979c79ddaaSMintz, Yuval 		   BIT(QEDE_STAT_PF_ONLY) | BIT(QEDE_STAT_AH_ONLY))
98133fac0eSSudarsana Kalluru static const struct {
99133fac0eSSudarsana Kalluru 	u64 offset;
100133fac0eSSudarsana Kalluru 	char string[ETH_GSTRING_LEN];
1019c79ddaaSMintz, Yuval 	unsigned long attr;
1029c79ddaaSMintz, Yuval #define QEDE_STAT_PF_ONLY	0
1039c79ddaaSMintz, Yuval #define QEDE_STAT_BB_ONLY	1
1049c79ddaaSMintz, Yuval #define QEDE_STAT_AH_ONLY	2
105133fac0eSSudarsana Kalluru } qede_stats_arr[] = {
106133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_bytes),
107133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_bytes),
108133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_bytes),
109133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_ucast_pkts),
110133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_mcast_pkts),
111133fac0eSSudarsana Kalluru 	QEDE_STAT(rx_bcast_pkts),
112133fac0eSSudarsana Kalluru 
113133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_bytes),
114133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_bytes),
115133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_bytes),
116133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_ucast_pkts),
117133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_mcast_pkts),
118133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_bcast_pkts),
119133fac0eSSudarsana Kalluru 
120133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_64_byte_packets),
121d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_65_to_127_byte_packets),
122d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_128_to_255_byte_packets),
123d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_256_to_511_byte_packets),
124d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_512_to_1023_byte_packets),
125d4967cf3SYuval Mintz 	QEDE_PF_STAT(rx_1024_to_1518_byte_packets),
1269c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_1519_to_1522_byte_packets),
1279c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_1519_to_2047_byte_packets),
1289c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_2048_to_4095_byte_packets),
1299c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_4096_to_9216_byte_packets),
1309c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(rx_9217_to_16383_byte_packets),
1319c79ddaaSMintz, Yuval 	QEDE_PF_AH_STAT(rx_1519_to_max_byte_packets),
132133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_64_byte_packets),
133133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_65_to_127_byte_packets),
134133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_128_to_255_byte_packets),
135133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_256_to_511_byte_packets),
136133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_512_to_1023_byte_packets),
137133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_1024_to_1518_byte_packets),
1389c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_1519_to_2047_byte_packets),
1399c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_2048_to_4095_byte_packets),
1409c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_4096_to_9216_byte_packets),
1419c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_9217_to_16383_byte_packets),
1429c79ddaaSMintz, Yuval 	QEDE_PF_AH_STAT(tx_1519_to_max_byte_packets),
143133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_mac_crtl_frames),
144133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_mac_ctrl_frames),
145133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pause_frames),
146133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pause_frames),
147133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_pfc_frames),
148133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(tx_pfc_frames),
149133fac0eSSudarsana Kalluru 
150133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_crc_errors),
151133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_align_errors),
152133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_carrier_errors),
153133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_oversize_packets),
154133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_jabbers),
155133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_undersize_packets),
156133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(rx_fragments),
1579c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_lpi_entry_count),
1589c79ddaaSMintz, Yuval 	QEDE_PF_BB_STAT(tx_total_collisions),
159133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_truncates),
160133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(brb_discards),
161133fac0eSSudarsana Kalluru 	QEDE_STAT(no_buff_discards),
162133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mftag_filter_discards),
163133fac0eSSudarsana Kalluru 	QEDE_PF_STAT(mac_filter_discards),
164608e00d0SManish Chopra 	QEDE_PF_STAT(gft_filter_drop),
165133fac0eSSudarsana Kalluru 	QEDE_STAT(tx_err_drop_pkts),
1661a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(ttl0_discard),
1671a5a366fSSudarsana Reddy Kalluru 	QEDE_STAT(packet_too_big_discard),
168133fac0eSSudarsana Kalluru 
169133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_pkts),
170133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_events),
171133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_aborts_num),
172133fac0eSSudarsana Kalluru 	QEDE_STAT(non_coalesced_pkts),
173133fac0eSSudarsana Kalluru 	QEDE_STAT(coalesced_bytes),
17432d26a68SSudarsana Reddy Kalluru 
17532d26a68SSudarsana Reddy Kalluru 	QEDE_STAT(link_change_count),
176133fac0eSSudarsana Kalluru };
177133fac0eSSudarsana Kalluru 
178133fac0eSSudarsana Kalluru #define QEDE_NUM_STATS	ARRAY_SIZE(qede_stats_arr)
1799c79ddaaSMintz, Yuval #define QEDE_STAT_IS_PF_ONLY(i) \
1809c79ddaaSMintz, Yuval 	test_bit(QEDE_STAT_PF_ONLY, &qede_stats_arr[i].attr)
1819c79ddaaSMintz, Yuval #define QEDE_STAT_IS_BB_ONLY(i) \
1829c79ddaaSMintz, Yuval 	test_bit(QEDE_STAT_BB_ONLY, &qede_stats_arr[i].attr)
1839c79ddaaSMintz, Yuval #define QEDE_STAT_IS_AH_ONLY(i) \
1849c79ddaaSMintz, Yuval 	test_bit(QEDE_STAT_AH_ONLY, &qede_stats_arr[i].attr)
185133fac0eSSudarsana Kalluru 
186f3e72109SYuval Mintz enum {
187f3e72109SYuval Mintz 	QEDE_PRI_FLAG_CMT,
188f3e72109SYuval Mintz 	QEDE_PRI_FLAG_LEN,
189f3e72109SYuval Mintz };
190f3e72109SYuval Mintz 
191f3e72109SYuval Mintz static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
192f3e72109SYuval Mintz 	"Coupled-Function",
193f3e72109SYuval Mintz };
194f3e72109SYuval Mintz 
1953044a02eSSudarsana Reddy Kalluru enum qede_ethtool_tests {
19616f46bf0SSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INT_LOOPBACK,
1973044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_INTERRUPT_TEST,
1983044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_MEMORY_TEST,
1993044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_REGISTER_TEST,
2003044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_CLOCK_TEST,
2017a4b21b7SMintz, Yuval 	QEDE_ETHTOOL_NVRAM_TEST,
2023044a02eSSudarsana Reddy Kalluru 	QEDE_ETHTOOL_TEST_MAX
2033044a02eSSudarsana Reddy Kalluru };
2043044a02eSSudarsana Reddy Kalluru 
2053044a02eSSudarsana Reddy Kalluru static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = {
20616f46bf0SSudarsana Reddy Kalluru 	"Internal loopback (offline)",
2073044a02eSSudarsana Reddy Kalluru 	"Interrupt (online)\t",
2083044a02eSSudarsana Reddy Kalluru 	"Memory (online)\t\t",
2093044a02eSSudarsana Reddy Kalluru 	"Register (online)\t",
2103044a02eSSudarsana Reddy Kalluru 	"Clock (online)\t\t",
2117a4b21b7SMintz, Yuval 	"Nvram (online)\t\t",
2123044a02eSSudarsana Reddy Kalluru };
2133044a02eSSudarsana Reddy Kalluru 
2144dbcd640SMintz, Yuval static void qede_get_strings_stats_txq(struct qede_dev *edev,
2154dbcd640SMintz, Yuval 				       struct qede_tx_queue *txq, u8 **buf)
2164dbcd640SMintz, Yuval {
2174dbcd640SMintz, Yuval 	int i;
2184dbcd640SMintz, Yuval 
2194dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
220cb6aeb07SMintz, Yuval 		if (txq->is_xdp)
221cb6aeb07SMintz, Yuval 			sprintf(*buf, "%d [XDP]: %s",
222cb6aeb07SMintz, Yuval 				QEDE_TXQ_XDP_TO_IDX(edev, txq),
223cb6aeb07SMintz, Yuval 				qede_tqstats_arr[i].string);
224cb6aeb07SMintz, Yuval 		else
2255e7baf0fSManish Chopra 			sprintf(*buf, "%d_%d: %s", txq->index, txq->cos,
2264dbcd640SMintz, Yuval 				qede_tqstats_arr[i].string);
2274dbcd640SMintz, Yuval 		*buf += ETH_GSTRING_LEN;
2284dbcd640SMintz, Yuval 	}
2294dbcd640SMintz, Yuval }
2304dbcd640SMintz, Yuval 
2314dbcd640SMintz, Yuval static void qede_get_strings_stats_rxq(struct qede_dev *edev,
2324dbcd640SMintz, Yuval 				       struct qede_rx_queue *rxq, u8 **buf)
2334dbcd640SMintz, Yuval {
2344dbcd640SMintz, Yuval 	int i;
2354dbcd640SMintz, Yuval 
2364dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
2374dbcd640SMintz, Yuval 		sprintf(*buf, "%d: %s", rxq->rxq_id,
2384dbcd640SMintz, Yuval 			qede_rqstats_arr[i].string);
2394dbcd640SMintz, Yuval 		*buf += ETH_GSTRING_LEN;
2404dbcd640SMintz, Yuval 	}
2414dbcd640SMintz, Yuval }
2424dbcd640SMintz, Yuval 
2439c79ddaaSMintz, Yuval static bool qede_is_irrelevant_stat(struct qede_dev *edev, int stat_index)
2449c79ddaaSMintz, Yuval {
2459c79ddaaSMintz, Yuval 	return (IS_VF(edev) && QEDE_STAT_IS_PF_ONLY(stat_index)) ||
2469c79ddaaSMintz, Yuval 	       (QEDE_IS_BB(edev) && QEDE_STAT_IS_AH_ONLY(stat_index)) ||
2479c79ddaaSMintz, Yuval 	       (QEDE_IS_AH(edev) && QEDE_STAT_IS_BB_ONLY(stat_index));
2489c79ddaaSMintz, Yuval }
2499c79ddaaSMintz, Yuval 
250133fac0eSSudarsana Kalluru static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
251133fac0eSSudarsana Kalluru {
2524dbcd640SMintz, Yuval 	struct qede_fastpath *fp;
2534dbcd640SMintz, Yuval 	int i;
254133fac0eSSudarsana Kalluru 
2554dbcd640SMintz, Yuval 	/* Account for queue statistics */
2564dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) {
2574dbcd640SMintz, Yuval 		fp = &edev->fp_array[i];
25868db9ec2SSudarsana Reddy Kalluru 
2594dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_RX)
2604dbcd640SMintz, Yuval 			qede_get_strings_stats_rxq(edev, fp->rxq, &buf);
2614dbcd640SMintz, Yuval 
262cb6aeb07SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_XDP)
263cb6aeb07SMintz, Yuval 			qede_get_strings_stats_txq(edev, fp->xdp_tx, &buf);
264cb6aeb07SMintz, Yuval 
2655e7baf0fSManish Chopra 		if (fp->type & QEDE_FASTPATH_TX) {
2665e7baf0fSManish Chopra 			int cos;
2675e7baf0fSManish Chopra 
2685e7baf0fSManish Chopra 			for_each_cos_in_txq(edev, cos)
2695e7baf0fSManish Chopra 				qede_get_strings_stats_txq(edev,
2705e7baf0fSManish Chopra 							   &fp->txq[cos], &buf);
2715e7baf0fSManish Chopra 		}
272cbbf049aSMintz, Yuval 	}
273cbbf049aSMintz, Yuval 
2744dbcd640SMintz, Yuval 	/* Account for non-queue statistics */
2754dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_STATS; i++) {
2769c79ddaaSMintz, Yuval 		if (qede_is_irrelevant_stat(edev, i))
277fefb0202SYuval Mintz 			continue;
2784dbcd640SMintz, Yuval 		strcpy(buf, qede_stats_arr[i].string);
2794dbcd640SMintz, Yuval 		buf += ETH_GSTRING_LEN;
280133fac0eSSudarsana Kalluru 	}
281133fac0eSSudarsana Kalluru }
282133fac0eSSudarsana Kalluru 
283133fac0eSSudarsana Kalluru static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
284133fac0eSSudarsana Kalluru {
285133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
286133fac0eSSudarsana Kalluru 
287133fac0eSSudarsana Kalluru 	switch (stringset) {
288133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
289133fac0eSSudarsana Kalluru 		qede_get_strings_stats(edev, buf);
290133fac0eSSudarsana Kalluru 		break;
291f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
292f3e72109SYuval Mintz 		memcpy(buf, qede_private_arr,
293f3e72109SYuval Mintz 		       ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN);
294f3e72109SYuval Mintz 		break;
2953044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
2963044a02eSSudarsana Reddy Kalluru 		memcpy(buf, qede_tests_str_arr,
2973044a02eSSudarsana Reddy Kalluru 		       ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX);
2983044a02eSSudarsana Reddy Kalluru 		break;
299133fac0eSSudarsana Kalluru 	default:
300133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
301133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
302133fac0eSSudarsana Kalluru 	}
303133fac0eSSudarsana Kalluru }
304133fac0eSSudarsana Kalluru 
3054dbcd640SMintz, Yuval static void qede_get_ethtool_stats_txq(struct qede_tx_queue *txq, u64 **buf)
3064dbcd640SMintz, Yuval {
3074dbcd640SMintz, Yuval 	int i;
3084dbcd640SMintz, Yuval 
3094dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
3104dbcd640SMintz, Yuval 		**buf = *((u64 *)(((void *)txq) + qede_tqstats_arr[i].offset));
3114dbcd640SMintz, Yuval 		(*buf)++;
3124dbcd640SMintz, Yuval 	}
3134dbcd640SMintz, Yuval }
3144dbcd640SMintz, Yuval 
3154dbcd640SMintz, Yuval static void qede_get_ethtool_stats_rxq(struct qede_rx_queue *rxq, u64 **buf)
3164dbcd640SMintz, Yuval {
3174dbcd640SMintz, Yuval 	int i;
3184dbcd640SMintz, Yuval 
3194dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
3204dbcd640SMintz, Yuval 		**buf = *((u64 *)(((void *)rxq) + qede_rqstats_arr[i].offset));
3214dbcd640SMintz, Yuval 		(*buf)++;
3224dbcd640SMintz, Yuval 	}
3234dbcd640SMintz, Yuval }
3244dbcd640SMintz, Yuval 
325133fac0eSSudarsana Kalluru static void qede_get_ethtool_stats(struct net_device *dev,
326133fac0eSSudarsana Kalluru 				   struct ethtool_stats *stats, u64 *buf)
327133fac0eSSudarsana Kalluru {
328133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
3294dbcd640SMintz, Yuval 	struct qede_fastpath *fp;
3304dbcd640SMintz, Yuval 	int i;
331133fac0eSSudarsana Kalluru 
332133fac0eSSudarsana Kalluru 	qede_fill_by_demand_stats(edev);
333133fac0eSSudarsana Kalluru 
334567b3c12SMintz, Yuval 	/* Need to protect the access to the fastpath array */
335567b3c12SMintz, Yuval 	__qede_lock(edev);
336567b3c12SMintz, Yuval 
3374dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) {
3384dbcd640SMintz, Yuval 		fp = &edev->fp_array[i];
339133fac0eSSudarsana Kalluru 
3404dbcd640SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_RX)
3414dbcd640SMintz, Yuval 			qede_get_ethtool_stats_rxq(fp->rxq, &buf);
34268db9ec2SSudarsana Reddy Kalluru 
343cb6aeb07SMintz, Yuval 		if (fp->type & QEDE_FASTPATH_XDP)
344cb6aeb07SMintz, Yuval 			qede_get_ethtool_stats_txq(fp->xdp_tx, &buf);
345cb6aeb07SMintz, Yuval 
3465e7baf0fSManish Chopra 		if (fp->type & QEDE_FASTPATH_TX) {
3475e7baf0fSManish Chopra 			int cos;
3485e7baf0fSManish Chopra 
3495e7baf0fSManish Chopra 			for_each_cos_in_txq(edev, cos)
3505e7baf0fSManish Chopra 				qede_get_ethtool_stats_txq(&fp->txq[cos], &buf);
3515e7baf0fSManish Chopra 		}
35268db9ec2SSudarsana Reddy Kalluru 	}
35368db9ec2SSudarsana Reddy Kalluru 
3544dbcd640SMintz, Yuval 	for (i = 0; i < QEDE_NUM_STATS; i++) {
3559c79ddaaSMintz, Yuval 		if (qede_is_irrelevant_stat(edev, i))
356fefb0202SYuval Mintz 			continue;
3574dbcd640SMintz, Yuval 		*buf = *((u64 *)(((void *)&edev->stats) +
3584dbcd640SMintz, Yuval 				 qede_stats_arr[i].offset));
3594dbcd640SMintz, Yuval 
3604dbcd640SMintz, Yuval 		buf++;
361fefb0202SYuval Mintz 	}
362133fac0eSSudarsana Kalluru 
363567b3c12SMintz, Yuval 	__qede_unlock(edev);
364133fac0eSSudarsana Kalluru }
365133fac0eSSudarsana Kalluru 
366133fac0eSSudarsana Kalluru static int qede_get_sset_count(struct net_device *dev, int stringset)
367133fac0eSSudarsana Kalluru {
368133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
3699c79ddaaSMintz, Yuval 	int num_stats = QEDE_NUM_STATS, i;
370133fac0eSSudarsana Kalluru 
371133fac0eSSudarsana Kalluru 	switch (stringset) {
372133fac0eSSudarsana Kalluru 	case ETH_SS_STATS:
373fefb0202SYuval Mintz 		for (i = 0; i < QEDE_NUM_STATS; i++)
3749c79ddaaSMintz, Yuval 			if (qede_is_irrelevant_stat(edev, i))
375fefb0202SYuval Mintz 				num_stats--;
3764dbcd640SMintz, Yuval 
3774dbcd640SMintz, Yuval 		/* Account for the Regular Tx statistics */
3785e7baf0fSManish Chopra 		num_stats += QEDE_TSS_COUNT(edev) * QEDE_NUM_TQSTATS *
3795e7baf0fSManish Chopra 				edev->dev_info.num_tc;
3804dbcd640SMintz, Yuval 
3814dbcd640SMintz, Yuval 		/* Account for the Regular Rx statistics */
3824dbcd640SMintz, Yuval 		num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS;
3834dbcd640SMintz, Yuval 
384cb6aeb07SMintz, Yuval 		/* Account for XDP statistics [if needed] */
385cb6aeb07SMintz, Yuval 		if (edev->xdp_prog)
386cb6aeb07SMintz, Yuval 			num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_TQSTATS;
3874dbcd640SMintz, Yuval 		return num_stats;
3884dbcd640SMintz, Yuval 
389f3e72109SYuval Mintz 	case ETH_SS_PRIV_FLAGS:
390f3e72109SYuval Mintz 		return QEDE_PRI_FLAG_LEN;
3913044a02eSSudarsana Reddy Kalluru 	case ETH_SS_TEST:
3926ecb0a0cSYuval Mintz 		if (!IS_VF(edev))
3933044a02eSSudarsana Reddy Kalluru 			return QEDE_ETHTOOL_TEST_MAX;
3946ecb0a0cSYuval Mintz 		else
3956ecb0a0cSYuval Mintz 			return 0;
396133fac0eSSudarsana Kalluru 	default:
397133fac0eSSudarsana Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
398133fac0eSSudarsana Kalluru 			   "Unsupported stringset 0x%08x\n", stringset);
399133fac0eSSudarsana Kalluru 		return -EINVAL;
400133fac0eSSudarsana Kalluru 	}
401133fac0eSSudarsana Kalluru }
402133fac0eSSudarsana Kalluru 
403f3e72109SYuval Mintz static u32 qede_get_priv_flags(struct net_device *dev)
404f3e72109SYuval Mintz {
405f3e72109SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
406f3e72109SYuval Mintz 
407f3e72109SYuval Mintz 	return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT;
408f3e72109SYuval Mintz }
409f3e72109SYuval Mintz 
410054c67d1SSudarsana Reddy Kalluru struct qede_link_mode_mapping {
411054c67d1SSudarsana Reddy Kalluru 	u32 qed_link_mode;
412054c67d1SSudarsana Reddy Kalluru 	u32 ethtool_link_mode;
413054c67d1SSudarsana Reddy Kalluru };
414054c67d1SSudarsana Reddy Kalluru 
415054c67d1SSudarsana Reddy Kalluru static const struct qede_link_mode_mapping qed_lm_map[] = {
416054c67d1SSudarsana Reddy Kalluru 	{QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
417054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
418054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
419054c67d1SSudarsana Reddy Kalluru 	{QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
420054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
421054c67d1SSudarsana Reddy Kalluru 	{QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
422054c67d1SSudarsana Reddy Kalluru 	{QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
423054c67d1SSudarsana Reddy Kalluru 	{QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
424054c67d1SSudarsana Reddy Kalluru 	{QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
425054c67d1SSudarsana Reddy Kalluru 	{QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
426054c67d1SSudarsana Reddy Kalluru 	{QED_LM_100000baseKR4_Full_BIT,
427054c67d1SSudarsana Reddy Kalluru 	 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
428054c67d1SSudarsana Reddy Kalluru };
429054c67d1SSudarsana Reddy Kalluru 
430054c67d1SSudarsana Reddy Kalluru #define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name)	\
431054c67d1SSudarsana Reddy Kalluru {								\
432054c67d1SSudarsana Reddy Kalluru 	int i;							\
433054c67d1SSudarsana Reddy Kalluru 								\
434d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
435054c67d1SSudarsana Reddy Kalluru 		if ((caps) & (qed_lm_map[i].qed_link_mode))	\
436054c67d1SSudarsana Reddy Kalluru 			__set_bit(qed_lm_map[i].ethtool_link_mode,\
437054c67d1SSudarsana Reddy Kalluru 				  lk_ksettings->link_modes.name); \
438054c67d1SSudarsana Reddy Kalluru 	}							\
439054c67d1SSudarsana Reddy Kalluru }
440054c67d1SSudarsana Reddy Kalluru 
441054c67d1SSudarsana Reddy Kalluru #define QEDE_ETHTOOL_TO_DRV_CAPS(caps, lk_ksettings, name)	\
442054c67d1SSudarsana Reddy Kalluru {								\
443054c67d1SSudarsana Reddy Kalluru 	int i;							\
444054c67d1SSudarsana Reddy Kalluru 								\
445d7455f6eSMintz, Yuval 	for (i = 0; i < ARRAY_SIZE(qed_lm_map); i++) {		\
446054c67d1SSudarsana Reddy Kalluru 		if (test_bit(qed_lm_map[i].ethtool_link_mode,	\
447054c67d1SSudarsana Reddy Kalluru 			     lk_ksettings->link_modes.name))	\
448054c67d1SSudarsana Reddy Kalluru 			caps |= qed_lm_map[i].qed_link_mode;	\
449054c67d1SSudarsana Reddy Kalluru 	}							\
450054c67d1SSudarsana Reddy Kalluru }
451054c67d1SSudarsana Reddy Kalluru 
452054c67d1SSudarsana Reddy Kalluru static int qede_get_link_ksettings(struct net_device *dev,
453054c67d1SSudarsana Reddy Kalluru 				   struct ethtool_link_ksettings *cmd)
454133fac0eSSudarsana Kalluru {
455054c67d1SSudarsana Reddy Kalluru 	struct ethtool_link_settings *base = &cmd->base;
456133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
457133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
458133fac0eSSudarsana Kalluru 
459567b3c12SMintz, Yuval 	__qede_lock(edev);
460567b3c12SMintz, Yuval 
461133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
462133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
463133fac0eSSudarsana Kalluru 
464054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
465054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.supported_caps, cmd, supported)
466054c67d1SSudarsana Reddy Kalluru 
467054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
468054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.advertised_caps, cmd, advertising)
469054c67d1SSudarsana Reddy Kalluru 
470054c67d1SSudarsana Reddy Kalluru 	ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
471054c67d1SSudarsana Reddy Kalluru 	QEDE_DRV_TO_ETHTOOL_CAPS(current_link.lp_caps, cmd, lp_advertising)
472054c67d1SSudarsana Reddy Kalluru 
473133fac0eSSudarsana Kalluru 	if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) {
474054c67d1SSudarsana Reddy Kalluru 		base->speed = current_link.speed;
475054c67d1SSudarsana Reddy Kalluru 		base->duplex = current_link.duplex;
476133fac0eSSudarsana Kalluru 	} else {
477054c67d1SSudarsana Reddy Kalluru 		base->speed = SPEED_UNKNOWN;
478054c67d1SSudarsana Reddy Kalluru 		base->duplex = DUPLEX_UNKNOWN;
479133fac0eSSudarsana Kalluru 	}
480567b3c12SMintz, Yuval 
481567b3c12SMintz, Yuval 	__qede_unlock(edev);
482567b3c12SMintz, Yuval 
483054c67d1SSudarsana Reddy Kalluru 	base->port = current_link.port;
484054c67d1SSudarsana Reddy Kalluru 	base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
485133fac0eSSudarsana Kalluru 			AUTONEG_DISABLE;
486133fac0eSSudarsana Kalluru 
487133fac0eSSudarsana Kalluru 	return 0;
488133fac0eSSudarsana Kalluru }
489133fac0eSSudarsana Kalluru 
490054c67d1SSudarsana Reddy Kalluru static int qede_set_link_ksettings(struct net_device *dev,
491054c67d1SSudarsana Reddy Kalluru 				   const struct ethtool_link_ksettings *cmd)
492133fac0eSSudarsana Kalluru {
493054c67d1SSudarsana Reddy Kalluru 	const struct ethtool_link_settings *base = &cmd->base;
494133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
495133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
496133fac0eSSudarsana Kalluru 	struct qed_link_params params;
497133fac0eSSudarsana Kalluru 
498fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
499054c67d1SSudarsana Reddy Kalluru 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
500133fac0eSSudarsana Kalluru 		return -EOPNOTSUPP;
501133fac0eSSudarsana Kalluru 	}
502133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
503133fac0eSSudarsana Kalluru 	memset(&params, 0, sizeof(params));
504133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
505133fac0eSSudarsana Kalluru 
506133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS;
507133fac0eSSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG;
508054c67d1SSudarsana Reddy Kalluru 	if (base->autoneg == AUTONEG_ENABLE) {
509161adb04Ssudarsana.kalluru@cavium.com 		if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
510161adb04Ssudarsana.kalluru@cavium.com 			DP_INFO(edev, "Auto negotiation is not supported\n");
511161adb04Ssudarsana.kalluru@cavium.com 			return -EOPNOTSUPP;
512161adb04Ssudarsana.kalluru@cavium.com 		}
513161adb04Ssudarsana.kalluru@cavium.com 
514133fac0eSSudarsana Kalluru 		params.autoneg = true;
515133fac0eSSudarsana Kalluru 		params.forced_speed = 0;
516054c67d1SSudarsana Reddy Kalluru 		QEDE_ETHTOOL_TO_DRV_CAPS(params.adv_speeds, cmd, advertising)
517133fac0eSSudarsana Kalluru 	} else {		/* forced speed */
518133fac0eSSudarsana Kalluru 		params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED;
519133fac0eSSudarsana Kalluru 		params.autoneg = false;
520054c67d1SSudarsana Reddy Kalluru 		params.forced_speed = base->speed;
521054c67d1SSudarsana Reddy Kalluru 		switch (base->speed) {
5229ac4c546SSudarsana Reddy Kalluru 		case SPEED_1000:
5239ac4c546SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
5249ac4c546SSudarsana Reddy Kalluru 			      QED_LM_1000baseT_Full_BIT)) {
5259ac4c546SSudarsana Reddy Kalluru 				DP_INFO(edev, "1G speed not supported\n");
5269ac4c546SSudarsana Reddy Kalluru 				return -EINVAL;
5279ac4c546SSudarsana Reddy Kalluru 			}
5289ac4c546SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_1000baseT_Full_BIT;
5299ac4c546SSudarsana Reddy Kalluru 			break;
530133fac0eSSudarsana Kalluru 		case SPEED_10000:
531133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
532054c67d1SSudarsana Reddy Kalluru 			      QED_LM_10000baseKR_Full_BIT)) {
533133fac0eSSudarsana Kalluru 				DP_INFO(edev, "10G speed not supported\n");
534133fac0eSSudarsana Kalluru 				return -EINVAL;
535133fac0eSSudarsana Kalluru 			}
536054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
537054c67d1SSudarsana Reddy Kalluru 			break;
538054c67d1SSudarsana Reddy Kalluru 		case SPEED_25000:
539054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
540054c67d1SSudarsana Reddy Kalluru 			      QED_LM_25000baseKR_Full_BIT)) {
541054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "25G speed not supported\n");
542054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
543054c67d1SSudarsana Reddy Kalluru 			}
544054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
545133fac0eSSudarsana Kalluru 			break;
546133fac0eSSudarsana Kalluru 		case SPEED_40000:
547133fac0eSSudarsana Kalluru 			if (!(current_link.supported_caps &
548054c67d1SSudarsana Reddy Kalluru 			      QED_LM_40000baseLR4_Full_BIT)) {
549133fac0eSSudarsana Kalluru 				DP_INFO(edev, "40G speed not supported\n");
550133fac0eSSudarsana Kalluru 				return -EINVAL;
551133fac0eSSudarsana Kalluru 			}
552054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
553054c67d1SSudarsana Reddy Kalluru 			break;
55416d5946aSYuval Mintz 		case SPEED_50000:
555054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
556054c67d1SSudarsana Reddy Kalluru 			      QED_LM_50000baseKR2_Full_BIT)) {
557054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "50G speed not supported\n");
558054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
559054c67d1SSudarsana Reddy Kalluru 			}
560054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
561054c67d1SSudarsana Reddy Kalluru 			break;
56216d5946aSYuval Mintz 		case SPEED_100000:
563054c67d1SSudarsana Reddy Kalluru 			if (!(current_link.supported_caps &
564054c67d1SSudarsana Reddy Kalluru 			      QED_LM_100000baseKR4_Full_BIT)) {
565054c67d1SSudarsana Reddy Kalluru 				DP_INFO(edev, "100G speed not supported\n");
566054c67d1SSudarsana Reddy Kalluru 				return -EINVAL;
567054c67d1SSudarsana Reddy Kalluru 			}
568054c67d1SSudarsana Reddy Kalluru 			params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
569133fac0eSSudarsana Kalluru 			break;
570133fac0eSSudarsana Kalluru 		default:
571054c67d1SSudarsana Reddy Kalluru 			DP_INFO(edev, "Unsupported speed %u\n", base->speed);
572133fac0eSSudarsana Kalluru 			return -EINVAL;
573133fac0eSSudarsana Kalluru 		}
574133fac0eSSudarsana Kalluru 	}
575133fac0eSSudarsana Kalluru 
576133fac0eSSudarsana Kalluru 	params.link_up = true;
577133fac0eSSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
578133fac0eSSudarsana Kalluru 
579133fac0eSSudarsana Kalluru 	return 0;
580133fac0eSSudarsana Kalluru }
581133fac0eSSudarsana Kalluru 
582133fac0eSSudarsana Kalluru static void qede_get_drvinfo(struct net_device *ndev,
583133fac0eSSudarsana Kalluru 			     struct ethtool_drvinfo *info)
584133fac0eSSudarsana Kalluru {
585133fac0eSSudarsana Kalluru 	char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN];
586133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
587133fac0eSSudarsana Kalluru 
588133fac0eSSudarsana Kalluru 	strlcpy(info->driver, "qede", sizeof(info->driver));
589133fac0eSSudarsana Kalluru 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
590133fac0eSSudarsana Kalluru 
591133fac0eSSudarsana Kalluru 	snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
592133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_major,
593133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_minor,
594133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_rev,
595133fac0eSSudarsana Kalluru 		 edev->dev_info.common.fw_eng);
596133fac0eSSudarsana Kalluru 
597133fac0eSSudarsana Kalluru 	snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d",
598133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 24) & 0xFF,
599133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 16) & 0xFF,
600133fac0eSSudarsana Kalluru 		 (edev->dev_info.common.mfw_rev >> 8) & 0xFF,
601133fac0eSSudarsana Kalluru 		 edev->dev_info.common.mfw_rev & 0xFF);
602133fac0eSSudarsana Kalluru 
603133fac0eSSudarsana Kalluru 	if ((strlen(storm) + strlen(mfw) + strlen("mfw storm  ")) <
604133fac0eSSudarsana Kalluru 	    sizeof(info->fw_version)) {
605133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
606133fac0eSSudarsana Kalluru 			 "mfw %s storm %s", mfw, storm);
607133fac0eSSudarsana Kalluru 	} else {
608133fac0eSSudarsana Kalluru 		snprintf(info->fw_version, sizeof(info->fw_version),
609133fac0eSSudarsana Kalluru 			 "%s %s", mfw, storm);
610133fac0eSSudarsana Kalluru 	}
611133fac0eSSudarsana Kalluru 
612133fac0eSSudarsana Kalluru 	strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info));
613133fac0eSSudarsana Kalluru }
614133fac0eSSudarsana Kalluru 
61514d39648SMintz, Yuval static void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
61614d39648SMintz, Yuval {
61714d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
61814d39648SMintz, Yuval 
61914d39648SMintz, Yuval 	if (edev->dev_info.common.wol_support) {
62014d39648SMintz, Yuval 		wol->supported = WAKE_MAGIC;
62114d39648SMintz, Yuval 		wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0;
62214d39648SMintz, Yuval 	}
62314d39648SMintz, Yuval }
62414d39648SMintz, Yuval 
62514d39648SMintz, Yuval static int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
62614d39648SMintz, Yuval {
62714d39648SMintz, Yuval 	struct qede_dev *edev = netdev_priv(ndev);
62814d39648SMintz, Yuval 	bool wol_requested;
62914d39648SMintz, Yuval 	int rc;
63014d39648SMintz, Yuval 
63114d39648SMintz, Yuval 	if (wol->wolopts & ~WAKE_MAGIC) {
63214d39648SMintz, Yuval 		DP_INFO(edev,
63314d39648SMintz, Yuval 			"Can't support WoL options other than magic-packet\n");
63414d39648SMintz, Yuval 		return -EINVAL;
63514d39648SMintz, Yuval 	}
63614d39648SMintz, Yuval 
63714d39648SMintz, Yuval 	wol_requested = !!(wol->wolopts & WAKE_MAGIC);
63814d39648SMintz, Yuval 	if (wol_requested == edev->wol_enabled)
63914d39648SMintz, Yuval 		return 0;
64014d39648SMintz, Yuval 
64114d39648SMintz, Yuval 	/* Need to actually change configuration */
64214d39648SMintz, Yuval 	if (!edev->dev_info.common.wol_support) {
64314d39648SMintz, Yuval 		DP_INFO(edev, "Device doesn't support WoL\n");
64414d39648SMintz, Yuval 		return -EINVAL;
64514d39648SMintz, Yuval 	}
64614d39648SMintz, Yuval 
64714d39648SMintz, Yuval 	rc = edev->ops->common->update_wol(edev->cdev, wol_requested);
64814d39648SMintz, Yuval 	if (!rc)
64914d39648SMintz, Yuval 		edev->wol_enabled = wol_requested;
65014d39648SMintz, Yuval 
65114d39648SMintz, Yuval 	return rc;
65214d39648SMintz, Yuval }
65314d39648SMintz, Yuval 
654133fac0eSSudarsana Kalluru static u32 qede_get_msglevel(struct net_device *ndev)
655133fac0eSSudarsana Kalluru {
656133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
657133fac0eSSudarsana Kalluru 
6581a635e48SYuval Mintz 	return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | edev->dp_module;
659133fac0eSSudarsana Kalluru }
660133fac0eSSudarsana Kalluru 
661133fac0eSSudarsana Kalluru static void qede_set_msglevel(struct net_device *ndev, u32 level)
662133fac0eSSudarsana Kalluru {
663133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
664133fac0eSSudarsana Kalluru 	u32 dp_module = 0;
665133fac0eSSudarsana Kalluru 	u8 dp_level = 0;
666133fac0eSSudarsana Kalluru 
667133fac0eSSudarsana Kalluru 	qede_config_debug(level, &dp_module, &dp_level);
668133fac0eSSudarsana Kalluru 
669133fac0eSSudarsana Kalluru 	edev->dp_level = dp_level;
670133fac0eSSudarsana Kalluru 	edev->dp_module = dp_module;
671133fac0eSSudarsana Kalluru 	edev->ops->common->update_msglvl(edev->cdev,
672133fac0eSSudarsana Kalluru 					 dp_module, dp_level);
673133fac0eSSudarsana Kalluru }
674133fac0eSSudarsana Kalluru 
67532a7a570SSudarsana Kalluru static int qede_nway_reset(struct net_device *dev)
67632a7a570SSudarsana Kalluru {
67732a7a570SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
67832a7a570SSudarsana Kalluru 	struct qed_link_output current_link;
67932a7a570SSudarsana Kalluru 	struct qed_link_params link_params;
68032a7a570SSudarsana Kalluru 
681fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
6821a635e48SYuval Mintz 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
683fe7cd2bfSYuval Mintz 		return -EOPNOTSUPP;
684fe7cd2bfSYuval Mintz 	}
685fe7cd2bfSYuval Mintz 
68632a7a570SSudarsana Kalluru 	if (!netif_running(dev))
68732a7a570SSudarsana Kalluru 		return 0;
68832a7a570SSudarsana Kalluru 
68932a7a570SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
69032a7a570SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
69132a7a570SSudarsana Kalluru 	if (!current_link.link_up)
69232a7a570SSudarsana Kalluru 		return 0;
69332a7a570SSudarsana Kalluru 
69432a7a570SSudarsana Kalluru 	/* Toggle the link */
69532a7a570SSudarsana Kalluru 	memset(&link_params, 0, sizeof(link_params));
69632a7a570SSudarsana Kalluru 	link_params.link_up = false;
69732a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
69832a7a570SSudarsana Kalluru 	link_params.link_up = true;
69932a7a570SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
70032a7a570SSudarsana Kalluru 
70132a7a570SSudarsana Kalluru 	return 0;
70232a7a570SSudarsana Kalluru }
70332a7a570SSudarsana Kalluru 
704133fac0eSSudarsana Kalluru static u32 qede_get_link(struct net_device *dev)
705133fac0eSSudarsana Kalluru {
706133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
707133fac0eSSudarsana Kalluru 	struct qed_link_output current_link;
708133fac0eSSudarsana Kalluru 
709133fac0eSSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
710133fac0eSSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
711133fac0eSSudarsana Kalluru 
712133fac0eSSudarsana Kalluru 	return current_link.link_up;
713133fac0eSSudarsana Kalluru }
714133fac0eSSudarsana Kalluru 
715ccfa110cSSudarsana Reddy Kalluru static int qede_flash_device(struct net_device *dev,
716ccfa110cSSudarsana Reddy Kalluru 			     struct ethtool_flash *flash)
717ccfa110cSSudarsana Reddy Kalluru {
718ccfa110cSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
719ccfa110cSSudarsana Reddy Kalluru 
720ccfa110cSSudarsana Reddy Kalluru 	return edev->ops->common->nvm_flash(edev->cdev, flash->data);
721ccfa110cSSudarsana Reddy Kalluru }
722ccfa110cSSudarsana Reddy Kalluru 
723d552fa84SSudarsana Reddy Kalluru static int qede_get_coalesce(struct net_device *dev,
724d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
725d552fa84SSudarsana Reddy Kalluru {
726bf5a94bfSRahul Verma 	void *rx_handle = NULL, *tx_handle = NULL;
727d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
728bf5a94bfSRahul Verma 	u16 rx_coal, tx_coal, i, rc = 0;
729bf5a94bfSRahul Verma 	struct qede_fastpath *fp;
730bf5a94bfSRahul Verma 
731bf5a94bfSRahul Verma 	rx_coal = QED_DEFAULT_RX_USECS;
732bf5a94bfSRahul Verma 	tx_coal = QED_DEFAULT_TX_USECS;
733d552fa84SSudarsana Reddy Kalluru 
734d552fa84SSudarsana Reddy Kalluru 	memset(coal, 0, sizeof(struct ethtool_coalesce));
735d2890deaSSudarsana Reddy Kalluru 
736bf5a94bfSRahul Verma 	__qede_lock(edev);
737bf5a94bfSRahul Verma 	if (edev->state == QEDE_STATE_OPEN) {
738bf5a94bfSRahul Verma 		for_each_queue(i) {
739bf5a94bfSRahul Verma 			fp = &edev->fp_array[i];
740d552fa84SSudarsana Reddy Kalluru 
741bf5a94bfSRahul Verma 			if (fp->type & QEDE_FASTPATH_RX) {
742bf5a94bfSRahul Verma 				rx_handle = fp->rxq->handle;
743bf5a94bfSRahul Verma 				break;
744bf5a94bfSRahul Verma 			}
745bf5a94bfSRahul Verma 		}
746bf5a94bfSRahul Verma 
747bf5a94bfSRahul Verma 		rc = edev->ops->get_coalesce(edev->cdev, &rx_coal, rx_handle);
748bf5a94bfSRahul Verma 		if (rc) {
749bf5a94bfSRahul Verma 			DP_INFO(edev, "Read Rx coalesce error\n");
750bf5a94bfSRahul Verma 			goto out;
751bf5a94bfSRahul Verma 		}
752bf5a94bfSRahul Verma 
753bf5a94bfSRahul Verma 		for_each_queue(i) {
7545e7baf0fSManish Chopra 			struct qede_tx_queue *txq;
7555e7baf0fSManish Chopra 
756bf5a94bfSRahul Verma 			fp = &edev->fp_array[i];
7575e7baf0fSManish Chopra 
7585e7baf0fSManish Chopra 			/* All TX queues of given fastpath uses same
7595e7baf0fSManish Chopra 			 * coalescing value, so no need to iterate over
7605e7baf0fSManish Chopra 			 * all TCs, TC0 txq should suffice.
7615e7baf0fSManish Chopra 			 */
762bf5a94bfSRahul Verma 			if (fp->type & QEDE_FASTPATH_TX) {
7635e7baf0fSManish Chopra 				txq = QEDE_FP_TC0_TXQ(fp);
7645e7baf0fSManish Chopra 				tx_handle = txq->handle;
765bf5a94bfSRahul Verma 				break;
766bf5a94bfSRahul Verma 			}
767bf5a94bfSRahul Verma 		}
768bf5a94bfSRahul Verma 
769bf5a94bfSRahul Verma 		rc = edev->ops->get_coalesce(edev->cdev, &tx_coal, tx_handle);
770bf5a94bfSRahul Verma 		if (rc)
771bf5a94bfSRahul Verma 			DP_INFO(edev, "Read Tx coalesce error\n");
772bf5a94bfSRahul Verma 	}
773bf5a94bfSRahul Verma 
774bf5a94bfSRahul Verma out:
775bf5a94bfSRahul Verma 	__qede_unlock(edev);
776bf5a94bfSRahul Verma 
777bf5a94bfSRahul Verma 	coal->rx_coalesce_usecs = rx_coal;
778bf5a94bfSRahul Verma 	coal->tx_coalesce_usecs = tx_coal;
779bf5a94bfSRahul Verma 
780bf5a94bfSRahul Verma 	return rc;
781d552fa84SSudarsana Reddy Kalluru }
782d552fa84SSudarsana Reddy Kalluru 
783d552fa84SSudarsana Reddy Kalluru static int qede_set_coalesce(struct net_device *dev,
784d552fa84SSudarsana Reddy Kalluru 			     struct ethtool_coalesce *coal)
785d552fa84SSudarsana Reddy Kalluru {
786d552fa84SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
787477f2d14SRahul Verma 	struct qede_fastpath *fp;
788d552fa84SSudarsana Reddy Kalluru 	int i, rc = 0;
789477f2d14SRahul Verma 	u16 rxc, txc;
790d552fa84SSudarsana Reddy Kalluru 
791d552fa84SSudarsana Reddy Kalluru 	if (!netif_running(dev)) {
792d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev, "Interface is down\n");
793d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
794d552fa84SSudarsana Reddy Kalluru 	}
795d552fa84SSudarsana Reddy Kalluru 
796d552fa84SSudarsana Reddy Kalluru 	if (coal->rx_coalesce_usecs > QED_COALESCE_MAX ||
797d552fa84SSudarsana Reddy Kalluru 	    coal->tx_coalesce_usecs > QED_COALESCE_MAX) {
798d552fa84SSudarsana Reddy Kalluru 		DP_INFO(edev,
799d552fa84SSudarsana Reddy Kalluru 			"Can't support requested %s coalesce value [max supported value %d]\n",
800477f2d14SRahul Verma 			coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx" :
801477f2d14SRahul Verma 			"tx", QED_COALESCE_MAX);
802d552fa84SSudarsana Reddy Kalluru 		return -EINVAL;
803d552fa84SSudarsana Reddy Kalluru 	}
804d552fa84SSudarsana Reddy Kalluru 
805d552fa84SSudarsana Reddy Kalluru 	rxc = (u16)coal->rx_coalesce_usecs;
806d552fa84SSudarsana Reddy Kalluru 	txc = (u16)coal->tx_coalesce_usecs;
8079a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
808477f2d14SRahul Verma 		fp = &edev->fp_array[i];
809477f2d14SRahul Verma 
810477f2d14SRahul Verma 		if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
811477f2d14SRahul Verma 			rc = edev->ops->common->set_coalesce(edev->cdev,
812477f2d14SRahul Verma 							     rxc, 0,
813477f2d14SRahul Verma 							     fp->rxq->handle);
814d552fa84SSudarsana Reddy Kalluru 			if (rc) {
815477f2d14SRahul Verma 				DP_INFO(edev,
816477f2d14SRahul Verma 					"Set RX coalesce error, rc = %d\n", rc);
817d552fa84SSudarsana Reddy Kalluru 				return rc;
818d552fa84SSudarsana Reddy Kalluru 			}
819d552fa84SSudarsana Reddy Kalluru 		}
820d552fa84SSudarsana Reddy Kalluru 
821477f2d14SRahul Verma 		if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
8225e7baf0fSManish Chopra 			struct qede_tx_queue *txq;
8235e7baf0fSManish Chopra 
8245e7baf0fSManish Chopra 			/* All TX queues of given fastpath uses same
8255e7baf0fSManish Chopra 			 * coalescing value, so no need to iterate over
8265e7baf0fSManish Chopra 			 * all TCs, TC0 txq should suffice.
8275e7baf0fSManish Chopra 			 */
8285e7baf0fSManish Chopra 			txq = QEDE_FP_TC0_TXQ(fp);
8295e7baf0fSManish Chopra 
830477f2d14SRahul Verma 			rc = edev->ops->common->set_coalesce(edev->cdev,
831477f2d14SRahul Verma 							     0, txc,
8325e7baf0fSManish Chopra 							     txq->handle);
833477f2d14SRahul Verma 			if (rc) {
834477f2d14SRahul Verma 				DP_INFO(edev,
835477f2d14SRahul Verma 					"Set TX coalesce error, rc = %d\n", rc);
836477f2d14SRahul Verma 				return rc;
837477f2d14SRahul Verma 			}
838477f2d14SRahul Verma 		}
839477f2d14SRahul Verma 	}
840477f2d14SRahul Verma 
841d552fa84SSudarsana Reddy Kalluru 	return rc;
842d552fa84SSudarsana Reddy Kalluru }
843d552fa84SSudarsana Reddy Kalluru 
84401ef7e05SSudarsana Kalluru static void qede_get_ringparam(struct net_device *dev,
84501ef7e05SSudarsana Kalluru 			       struct ethtool_ringparam *ering)
84601ef7e05SSudarsana Kalluru {
84701ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
84801ef7e05SSudarsana Kalluru 
84901ef7e05SSudarsana Kalluru 	ering->rx_max_pending = NUM_RX_BDS_MAX;
85001ef7e05SSudarsana Kalluru 	ering->rx_pending = edev->q_num_rx_buffers;
85101ef7e05SSudarsana Kalluru 	ering->tx_max_pending = NUM_TX_BDS_MAX;
85201ef7e05SSudarsana Kalluru 	ering->tx_pending = edev->q_num_tx_buffers;
85301ef7e05SSudarsana Kalluru }
85401ef7e05SSudarsana Kalluru 
85501ef7e05SSudarsana Kalluru static int qede_set_ringparam(struct net_device *dev,
85601ef7e05SSudarsana Kalluru 			      struct ethtool_ringparam *ering)
85701ef7e05SSudarsana Kalluru {
85801ef7e05SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
85901ef7e05SSudarsana Kalluru 
86001ef7e05SSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
86101ef7e05SSudarsana Kalluru 		   "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
86201ef7e05SSudarsana Kalluru 		   ering->rx_pending, ering->tx_pending);
86301ef7e05SSudarsana Kalluru 
86401ef7e05SSudarsana Kalluru 	/* Validate legality of configuration */
86501ef7e05SSudarsana Kalluru 	if (ering->rx_pending > NUM_RX_BDS_MAX ||
86601ef7e05SSudarsana Kalluru 	    ering->rx_pending < NUM_RX_BDS_MIN ||
86701ef7e05SSudarsana Kalluru 	    ering->tx_pending > NUM_TX_BDS_MAX ||
86801ef7e05SSudarsana Kalluru 	    ering->tx_pending < NUM_TX_BDS_MIN) {
86901ef7e05SSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
87001ef7e05SSudarsana Kalluru 			   "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n",
87101ef7e05SSudarsana Kalluru 			   NUM_RX_BDS_MIN, NUM_RX_BDS_MAX,
87201ef7e05SSudarsana Kalluru 			   NUM_TX_BDS_MIN, NUM_TX_BDS_MAX);
87301ef7e05SSudarsana Kalluru 		return -EINVAL;
87401ef7e05SSudarsana Kalluru 	}
87501ef7e05SSudarsana Kalluru 
87601ef7e05SSudarsana Kalluru 	/* Change ring size and re-load */
87701ef7e05SSudarsana Kalluru 	edev->q_num_rx_buffers = ering->rx_pending;
87801ef7e05SSudarsana Kalluru 	edev->q_num_tx_buffers = ering->tx_pending;
87901ef7e05SSudarsana Kalluru 
880567b3c12SMintz, Yuval 	qede_reload(edev, NULL, false);
88101ef7e05SSudarsana Kalluru 
88201ef7e05SSudarsana Kalluru 	return 0;
88301ef7e05SSudarsana Kalluru }
88401ef7e05SSudarsana Kalluru 
8850f7db144SSudarsana Kalluru static void qede_get_pauseparam(struct net_device *dev,
8860f7db144SSudarsana Kalluru 				struct ethtool_pauseparam *epause)
8870f7db144SSudarsana Kalluru {
8880f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
8890f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
8900f7db144SSudarsana Kalluru 
8910f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
8920f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
8930f7db144SSudarsana Kalluru 
8940f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
8950f7db144SSudarsana Kalluru 		epause->autoneg = true;
8960f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE)
8970f7db144SSudarsana Kalluru 		epause->rx_pause = true;
8980f7db144SSudarsana Kalluru 	if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE)
8990f7db144SSudarsana Kalluru 		epause->tx_pause = true;
9000f7db144SSudarsana Kalluru 
9010f7db144SSudarsana Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
9020f7db144SSudarsana Kalluru 		   "ethtool_pauseparam: cmd %d  autoneg %d  rx_pause %d  tx_pause %d\n",
9030f7db144SSudarsana Kalluru 		   epause->cmd, epause->autoneg, epause->rx_pause,
9040f7db144SSudarsana Kalluru 		   epause->tx_pause);
9050f7db144SSudarsana Kalluru }
9060f7db144SSudarsana Kalluru 
9070f7db144SSudarsana Kalluru static int qede_set_pauseparam(struct net_device *dev,
9080f7db144SSudarsana Kalluru 			       struct ethtool_pauseparam *epause)
9090f7db144SSudarsana Kalluru {
9100f7db144SSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9110f7db144SSudarsana Kalluru 	struct qed_link_params params;
9120f7db144SSudarsana Kalluru 	struct qed_link_output current_link;
9130f7db144SSudarsana Kalluru 
914fe7cd2bfSYuval Mintz 	if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
9150f7db144SSudarsana Kalluru 		DP_INFO(edev,
916fe7cd2bfSYuval Mintz 			"Pause settings are not allowed to be changed\n");
9170f7db144SSudarsana Kalluru 		return -EOPNOTSUPP;
9180f7db144SSudarsana Kalluru 	}
9190f7db144SSudarsana Kalluru 
9200f7db144SSudarsana Kalluru 	memset(&current_link, 0, sizeof(current_link));
9210f7db144SSudarsana Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
9220f7db144SSudarsana Kalluru 
9230f7db144SSudarsana Kalluru 	memset(&params, 0, sizeof(params));
9240f7db144SSudarsana Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG;
9250f7db144SSudarsana Kalluru 	if (epause->autoneg) {
926d194fd26SYuval Mintz 		if (!(current_link.supported_caps & QED_LM_Autoneg_BIT)) {
9270f7db144SSudarsana Kalluru 			DP_INFO(edev, "autoneg not supported\n");
9280f7db144SSudarsana Kalluru 			return -EINVAL;
9290f7db144SSudarsana Kalluru 		}
9300f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
9310f7db144SSudarsana Kalluru 	}
9320f7db144SSudarsana Kalluru 	if (epause->rx_pause)
9330f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_RX_ENABLE;
9340f7db144SSudarsana Kalluru 	if (epause->tx_pause)
9350f7db144SSudarsana Kalluru 		params.pause_config |= QED_LINK_PAUSE_TX_ENABLE;
9360f7db144SSudarsana Kalluru 
9370f7db144SSudarsana Kalluru 	params.link_up = true;
9380f7db144SSudarsana Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
9390f7db144SSudarsana Kalluru 
9400f7db144SSudarsana Kalluru 	return 0;
9410f7db144SSudarsana Kalluru }
9420f7db144SSudarsana Kalluru 
943e0971c83STomer Tayar static void qede_get_regs(struct net_device *ndev,
944e0971c83STomer Tayar 			  struct ethtool_regs *regs, void *buffer)
945e0971c83STomer Tayar {
946e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
947e0971c83STomer Tayar 
948e0971c83STomer Tayar 	regs->version = 0;
949e0971c83STomer Tayar 	memset(buffer, 0, regs->len);
950e0971c83STomer Tayar 
951e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
952e0971c83STomer Tayar 		edev->ops->common->dbg_all_data(edev->cdev, buffer);
953e0971c83STomer Tayar }
954e0971c83STomer Tayar 
955e0971c83STomer Tayar static int qede_get_regs_len(struct net_device *ndev)
956e0971c83STomer Tayar {
957e0971c83STomer Tayar 	struct qede_dev *edev = netdev_priv(ndev);
958e0971c83STomer Tayar 
959e0971c83STomer Tayar 	if (edev->ops && edev->ops->common)
960e0971c83STomer Tayar 		return edev->ops->common->dbg_all_data_size(edev->cdev);
961e0971c83STomer Tayar 	else
962e0971c83STomer Tayar 		return -EINVAL;
963e0971c83STomer Tayar }
964e0971c83STomer Tayar 
965567b3c12SMintz, Yuval static void qede_update_mtu(struct qede_dev *edev,
966567b3c12SMintz, Yuval 			    struct qede_reload_args *args)
967133fac0eSSudarsana Kalluru {
968567b3c12SMintz, Yuval 	edev->ndev->mtu = args->u.mtu;
969133fac0eSSudarsana Kalluru }
970133fac0eSSudarsana Kalluru 
971133fac0eSSudarsana Kalluru /* Netdevice NDOs */
972133fac0eSSudarsana Kalluru int qede_change_mtu(struct net_device *ndev, int new_mtu)
973133fac0eSSudarsana Kalluru {
974133fac0eSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(ndev);
975567b3c12SMintz, Yuval 	struct qede_reload_args args;
976133fac0eSSudarsana Kalluru 
977133fac0eSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
978133fac0eSSudarsana Kalluru 		   "Configuring MTU size of %d\n", new_mtu);
979133fac0eSSudarsana Kalluru 
98018c602deSMichael Chan 	if (new_mtu > PAGE_SIZE)
98118c602deSMichael Chan 		ndev->features &= ~NETIF_F_GRO_HW;
98218c602deSMichael Chan 
983133fac0eSSudarsana Kalluru 	/* Set the mtu field and re-start the interface if needed */
984567b3c12SMintz, Yuval 	args.u.mtu = new_mtu;
985567b3c12SMintz, Yuval 	args.func = &qede_update_mtu;
986567b3c12SMintz, Yuval 	qede_reload(edev, &args, false);
987133fac0eSSudarsana Kalluru 
988567b3c12SMintz, Yuval 	edev->ops->common->update_mtu(edev->cdev, new_mtu);
9890fefbfbaSSudarsana Kalluru 
990133fac0eSSudarsana Kalluru 	return 0;
991133fac0eSSudarsana Kalluru }
992133fac0eSSudarsana Kalluru 
9938edf049dSSudarsana Kalluru static void qede_get_channels(struct net_device *dev,
9948edf049dSSudarsana Kalluru 			      struct ethtool_channels *channels)
9958edf049dSSudarsana Kalluru {
9968edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
9978edf049dSSudarsana Kalluru 
9988edf049dSSudarsana Kalluru 	channels->max_combined = QEDE_MAX_RSS_CNT(edev);
999bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_rx = QEDE_MAX_RSS_CNT(edev);
1000bdc8cbd3SSudarsana Reddy Kalluru 	channels->max_tx = QEDE_MAX_RSS_CNT(edev);
10019a4d7e86SSudarsana Reddy Kalluru 	channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx -
10029a4d7e86SSudarsana Reddy Kalluru 					edev->fp_num_rx;
10039a4d7e86SSudarsana Reddy Kalluru 	channels->tx_count = edev->fp_num_tx;
10049a4d7e86SSudarsana Reddy Kalluru 	channels->rx_count = edev->fp_num_rx;
10058edf049dSSudarsana Kalluru }
10068edf049dSSudarsana Kalluru 
10078edf049dSSudarsana Kalluru static int qede_set_channels(struct net_device *dev,
10088edf049dSSudarsana Kalluru 			     struct ethtool_channels *channels)
10098edf049dSSudarsana Kalluru {
10108edf049dSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
10119a4d7e86SSudarsana Reddy Kalluru 	u32 count;
10128edf049dSSudarsana Kalluru 
10138edf049dSSudarsana Kalluru 	DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
10148edf049dSSudarsana Kalluru 		   "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
10158edf049dSSudarsana Kalluru 		   channels->rx_count, channels->tx_count,
10168edf049dSSudarsana Kalluru 		   channels->other_count, channels->combined_count);
10178edf049dSSudarsana Kalluru 
10189a4d7e86SSudarsana Reddy Kalluru 	count = channels->rx_count + channels->tx_count +
10199a4d7e86SSudarsana Reddy Kalluru 			channels->combined_count;
10209a4d7e86SSudarsana Reddy Kalluru 
10219a4d7e86SSudarsana Reddy Kalluru 	/* We don't support `other' channels */
10229a4d7e86SSudarsana Reddy Kalluru 	if (channels->other_count) {
10238edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
10248edf049dSSudarsana Kalluru 			   "command parameters not supported\n");
10258edf049dSSudarsana Kalluru 		return -EINVAL;
10268edf049dSSudarsana Kalluru 	}
10278edf049dSSudarsana Kalluru 
10289a4d7e86SSudarsana Reddy Kalluru 	if (!(channels->combined_count || (channels->rx_count &&
10299a4d7e86SSudarsana Reddy Kalluru 					   channels->tx_count))) {
10309a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
10319a4d7e86SSudarsana Reddy Kalluru 			   "need to request at least one transmit and one receive channel\n");
10329a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
10339a4d7e86SSudarsana Reddy Kalluru 	}
10349a4d7e86SSudarsana Reddy Kalluru 
10359a4d7e86SSudarsana Reddy Kalluru 	if (count > QEDE_MAX_RSS_CNT(edev)) {
10369a4d7e86SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
10379a4d7e86SSudarsana Reddy Kalluru 			   "requested channels = %d max supported channels = %d\n",
10389a4d7e86SSudarsana Reddy Kalluru 			   count, QEDE_MAX_RSS_CNT(edev));
10399a4d7e86SSudarsana Reddy Kalluru 		return -EINVAL;
10409a4d7e86SSudarsana Reddy Kalluru 	}
10419a4d7e86SSudarsana Reddy Kalluru 
10428edf049dSSudarsana Kalluru 	/* Check if there was a change in the active parameters */
10439a4d7e86SSudarsana Reddy Kalluru 	if ((count == QEDE_QUEUE_CNT(edev)) &&
10449a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count == edev->fp_num_tx) &&
10459a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count == edev->fp_num_rx)) {
10468edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
10478edf049dSSudarsana Kalluru 			   "No change in active parameters\n");
10488edf049dSSudarsana Kalluru 		return 0;
10498edf049dSSudarsana Kalluru 	}
10508edf049dSSudarsana Kalluru 
10518edf049dSSudarsana Kalluru 	/* We need the number of queues to be divisible between the hwfns */
10529a4d7e86SSudarsana Reddy Kalluru 	if ((count % edev->dev_info.common.num_hwfns) ||
10539a4d7e86SSudarsana Reddy Kalluru 	    (channels->tx_count % edev->dev_info.common.num_hwfns) ||
10549a4d7e86SSudarsana Reddy Kalluru 	    (channels->rx_count % edev->dev_info.common.num_hwfns)) {
10558edf049dSSudarsana Kalluru 		DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
10569a4d7e86SSudarsana Reddy Kalluru 			   "Number of channels must be divisible by %04x\n",
10578edf049dSSudarsana Kalluru 			   edev->dev_info.common.num_hwfns);
10588edf049dSSudarsana Kalluru 		return -EINVAL;
10598edf049dSSudarsana Kalluru 	}
10608edf049dSSudarsana Kalluru 
10618edf049dSSudarsana Kalluru 	/* Set number of queues and reload if necessary */
10629a4d7e86SSudarsana Reddy Kalluru 	edev->req_queues = count;
10639a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_tx = channels->tx_count;
10649a4d7e86SSudarsana Reddy Kalluru 	edev->req_num_rx = channels->rx_count;
1065ed0dd915SSudarsana Reddy Kalluru 	/* Reset the indirection table if rx queue count is updated */
1066ed0dd915SSudarsana Reddy Kalluru 	if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) {
1067ed0dd915SSudarsana Reddy Kalluru 		edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED;
1068f29ffdb6SMintz, Yuval 		memset(edev->rss_ind_table, 0, sizeof(edev->rss_ind_table));
1069ed0dd915SSudarsana Reddy Kalluru 	}
1070ed0dd915SSudarsana Reddy Kalluru 
1071567b3c12SMintz, Yuval 	qede_reload(edev, NULL, false);
10728edf049dSSudarsana Kalluru 
10738edf049dSSudarsana Kalluru 	return 0;
10748edf049dSSudarsana Kalluru }
10758edf049dSSudarsana Kalluru 
10764c55215cSSudarsana Reddy Kalluru static int qede_get_ts_info(struct net_device *dev,
10774c55215cSSudarsana Reddy Kalluru 			    struct ethtool_ts_info *info)
10784c55215cSSudarsana Reddy Kalluru {
10794c55215cSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
10804c55215cSSudarsana Reddy Kalluru 
10814c55215cSSudarsana Reddy Kalluru 	return qede_ptp_get_ts_info(edev, info);
10824c55215cSSudarsana Reddy Kalluru }
10834c55215cSSudarsana Reddy Kalluru 
10843d971cbdSSudarsana Kalluru static int qede_set_phys_id(struct net_device *dev,
10853d971cbdSSudarsana Kalluru 			    enum ethtool_phys_id_state state)
10863d971cbdSSudarsana Kalluru {
10873d971cbdSSudarsana Kalluru 	struct qede_dev *edev = netdev_priv(dev);
10883d971cbdSSudarsana Kalluru 	u8 led_state = 0;
10893d971cbdSSudarsana Kalluru 
10903d971cbdSSudarsana Kalluru 	switch (state) {
10913d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ACTIVE:
10923d971cbdSSudarsana Kalluru 		return 1;	/* cycle on/off once per second */
10933d971cbdSSudarsana Kalluru 
10943d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_ON:
10953d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_ON;
10963d971cbdSSudarsana Kalluru 		break;
10973d971cbdSSudarsana Kalluru 
10983d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_OFF:
10993d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_OFF;
11003d971cbdSSudarsana Kalluru 		break;
11013d971cbdSSudarsana Kalluru 
11023d971cbdSSudarsana Kalluru 	case ETHTOOL_ID_INACTIVE:
11033d971cbdSSudarsana Kalluru 		led_state = QED_LED_MODE_RESTORE;
11043d971cbdSSudarsana Kalluru 		break;
11053d971cbdSSudarsana Kalluru 	}
11063d971cbdSSudarsana Kalluru 
11073d971cbdSSudarsana Kalluru 	edev->ops->common->set_led(edev->cdev, led_state);
11083d971cbdSSudarsana Kalluru 
11093d971cbdSSudarsana Kalluru 	return 0;
11103d971cbdSSudarsana Kalluru }
11113d971cbdSSudarsana Kalluru 
1112961acdeaSSudarsana Reddy Kalluru static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
1113961acdeaSSudarsana Reddy Kalluru {
1114961acdeaSSudarsana Reddy Kalluru 	info->data = RXH_IP_SRC | RXH_IP_DST;
1115961acdeaSSudarsana Reddy Kalluru 
1116961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
1117961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
1118961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
1119961acdeaSSudarsana Reddy Kalluru 		info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
1120961acdeaSSudarsana Reddy Kalluru 		break;
1121961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
1122f29ffdb6SMintz, Yuval 		if (edev->rss_caps & QED_RSS_IPV4_UDP)
1123961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
1124961acdeaSSudarsana Reddy Kalluru 		break;
1125961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
1126f29ffdb6SMintz, Yuval 		if (edev->rss_caps & QED_RSS_IPV6_UDP)
1127961acdeaSSudarsana Reddy Kalluru 			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
1128961acdeaSSudarsana Reddy Kalluru 		break;
1129961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
1130961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
1131961acdeaSSudarsana Reddy Kalluru 		break;
1132961acdeaSSudarsana Reddy Kalluru 	default:
1133961acdeaSSudarsana Reddy Kalluru 		info->data = 0;
1134961acdeaSSudarsana Reddy Kalluru 		break;
1135961acdeaSSudarsana Reddy Kalluru 	}
1136961acdeaSSudarsana Reddy Kalluru 
1137961acdeaSSudarsana Reddy Kalluru 	return 0;
1138961acdeaSSudarsana Reddy Kalluru }
1139961acdeaSSudarsana Reddy Kalluru 
1140961acdeaSSudarsana Reddy Kalluru static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
1141ec9b8dbdSChopra, Manish 			  u32 *rule_locs)
1142961acdeaSSudarsana Reddy Kalluru {
1143961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1144ec9b8dbdSChopra, Manish 	int rc = 0;
1145961acdeaSSudarsana Reddy Kalluru 
1146961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
1147961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXRINGS:
11489a4d7e86SSudarsana Reddy Kalluru 		info->data = QEDE_RSS_COUNT(edev);
1149ec9b8dbdSChopra, Manish 		break;
1150961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_GRXFH:
1151ec9b8dbdSChopra, Manish 		rc = qede_get_rss_flags(edev, info);
1152ec9b8dbdSChopra, Manish 		break;
1153ec9b8dbdSChopra, Manish 	case ETHTOOL_GRXCLSRLCNT:
1154ec9b8dbdSChopra, Manish 		info->rule_cnt = qede_get_arfs_filter_count(edev);
1155ec9b8dbdSChopra, Manish 		info->data = QEDE_RFS_MAX_FLTR;
1156ec9b8dbdSChopra, Manish 		break;
1157ec9b8dbdSChopra, Manish 	case ETHTOOL_GRXCLSRULE:
1158ec9b8dbdSChopra, Manish 		rc = qede_get_cls_rule_entry(edev, info);
1159ec9b8dbdSChopra, Manish 		break;
1160ec9b8dbdSChopra, Manish 	case ETHTOOL_GRXCLSRLALL:
1161ec9b8dbdSChopra, Manish 		rc = qede_get_cls_rule_all(edev, info, rule_locs);
1162ec9b8dbdSChopra, Manish 		break;
1163961acdeaSSudarsana Reddy Kalluru 	default:
1164961acdeaSSudarsana Reddy Kalluru 		DP_ERR(edev, "Command parameters not supported\n");
1165ec9b8dbdSChopra, Manish 		rc = -EOPNOTSUPP;
1166961acdeaSSudarsana Reddy Kalluru 	}
1167ec9b8dbdSChopra, Manish 
1168ec9b8dbdSChopra, Manish 	return rc;
1169961acdeaSSudarsana Reddy Kalluru }
1170961acdeaSSudarsana Reddy Kalluru 
1171961acdeaSSudarsana Reddy Kalluru static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
1172961acdeaSSudarsana Reddy Kalluru {
1173f29ffdb6SMintz, Yuval 	struct qed_update_vport_params *vport_update_params;
1174961acdeaSSudarsana Reddy Kalluru 	u8 set_caps = 0, clr_caps = 0;
1175f29ffdb6SMintz, Yuval 	int rc = 0;
1176961acdeaSSudarsana Reddy Kalluru 
1177961acdeaSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
1178961acdeaSSudarsana Reddy Kalluru 		   "Set rss flags command parameters: flow type = %d, data = %llu\n",
1179961acdeaSSudarsana Reddy Kalluru 		   info->flow_type, info->data);
1180961acdeaSSudarsana Reddy Kalluru 
1181961acdeaSSudarsana Reddy Kalluru 	switch (info->flow_type) {
1182961acdeaSSudarsana Reddy Kalluru 	case TCP_V4_FLOW:
1183961acdeaSSudarsana Reddy Kalluru 	case TCP_V6_FLOW:
1184961acdeaSSudarsana Reddy Kalluru 		/* For TCP only 4-tuple hash is supported */
1185961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
1186961acdeaSSudarsana Reddy Kalluru 				  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1187961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1188961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1189961acdeaSSudarsana Reddy Kalluru 		}
1190961acdeaSSudarsana Reddy Kalluru 		return 0;
1191961acdeaSSudarsana Reddy Kalluru 	case UDP_V4_FLOW:
1192961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
1193961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
1194961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1195961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV4_UDP;
1196961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1197961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
1198961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
1199961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV4_UDP;
1200961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1201961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
1202961acdeaSSudarsana Reddy Kalluru 		} else {
1203961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1204961acdeaSSudarsana Reddy Kalluru 		}
1205961acdeaSSudarsana Reddy Kalluru 		break;
1206961acdeaSSudarsana Reddy Kalluru 	case UDP_V6_FLOW:
1207961acdeaSSudarsana Reddy Kalluru 		/* For UDP either 2-tuple hash or 4-tuple hash is supported */
1208961acdeaSSudarsana Reddy Kalluru 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
1209961acdeaSSudarsana Reddy Kalluru 				   RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
1210961acdeaSSudarsana Reddy Kalluru 			set_caps = QED_RSS_IPV6_UDP;
1211961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1212961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple enabled\n");
1213961acdeaSSudarsana Reddy Kalluru 		} else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
1214961acdeaSSudarsana Reddy Kalluru 			clr_caps = QED_RSS_IPV6_UDP;
1215961acdeaSSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
1216961acdeaSSudarsana Reddy Kalluru 				   "UDP 4-tuple disabled\n");
1217961acdeaSSudarsana Reddy Kalluru 		} else {
1218961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1219961acdeaSSudarsana Reddy Kalluru 		}
1220961acdeaSSudarsana Reddy Kalluru 		break;
1221961acdeaSSudarsana Reddy Kalluru 	case IPV4_FLOW:
1222961acdeaSSudarsana Reddy Kalluru 	case IPV6_FLOW:
1223961acdeaSSudarsana Reddy Kalluru 		/* For IP only 2-tuple hash is supported */
1224961acdeaSSudarsana Reddy Kalluru 		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
1225961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1226961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1227961acdeaSSudarsana Reddy Kalluru 		}
1228961acdeaSSudarsana Reddy Kalluru 		return 0;
1229961acdeaSSudarsana Reddy Kalluru 	case SCTP_V4_FLOW:
1230961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V4_FLOW:
1231961acdeaSSudarsana Reddy Kalluru 	case AH_V4_FLOW:
1232961acdeaSSudarsana Reddy Kalluru 	case ESP_V4_FLOW:
1233961acdeaSSudarsana Reddy Kalluru 	case SCTP_V6_FLOW:
1234961acdeaSSudarsana Reddy Kalluru 	case AH_ESP_V6_FLOW:
1235961acdeaSSudarsana Reddy Kalluru 	case AH_V6_FLOW:
1236961acdeaSSudarsana Reddy Kalluru 	case ESP_V6_FLOW:
1237961acdeaSSudarsana Reddy Kalluru 	case IP_USER_FLOW:
1238961acdeaSSudarsana Reddy Kalluru 	case ETHER_FLOW:
1239961acdeaSSudarsana Reddy Kalluru 		/* RSS is not supported for these protocols */
1240961acdeaSSudarsana Reddy Kalluru 		if (info->data) {
1241961acdeaSSudarsana Reddy Kalluru 			DP_INFO(edev, "Command parameters not supported\n");
1242961acdeaSSudarsana Reddy Kalluru 			return -EINVAL;
1243961acdeaSSudarsana Reddy Kalluru 		}
1244961acdeaSSudarsana Reddy Kalluru 		return 0;
1245961acdeaSSudarsana Reddy Kalluru 	default:
1246961acdeaSSudarsana Reddy Kalluru 		return -EINVAL;
1247961acdeaSSudarsana Reddy Kalluru 	}
1248961acdeaSSudarsana Reddy Kalluru 
1249961acdeaSSudarsana Reddy Kalluru 	/* No action is needed if there is no change in the rss capability */
1250f29ffdb6SMintz, Yuval 	if (edev->rss_caps == ((edev->rss_caps & ~clr_caps) | set_caps))
1251961acdeaSSudarsana Reddy Kalluru 		return 0;
1252961acdeaSSudarsana Reddy Kalluru 
1253961acdeaSSudarsana Reddy Kalluru 	/* Update internal configuration */
1254f29ffdb6SMintz, Yuval 	edev->rss_caps = ((edev->rss_caps & ~clr_caps) | set_caps);
1255961acdeaSSudarsana Reddy Kalluru 	edev->rss_params_inited |= QEDE_RSS_CAPS_INITED;
1256961acdeaSSudarsana Reddy Kalluru 
1257961acdeaSSudarsana Reddy Kalluru 	/* Re-configure if possible */
1258f29ffdb6SMintz, Yuval 	__qede_lock(edev);
1259f29ffdb6SMintz, Yuval 	if (edev->state == QEDE_STATE_OPEN) {
1260f29ffdb6SMintz, Yuval 		vport_update_params = vzalloc(sizeof(*vport_update_params));
1261f29ffdb6SMintz, Yuval 		if (!vport_update_params) {
1262f29ffdb6SMintz, Yuval 			__qede_unlock(edev);
1263f29ffdb6SMintz, Yuval 			return -ENOMEM;
1264961acdeaSSudarsana Reddy Kalluru 		}
1265f29ffdb6SMintz, Yuval 		qede_fill_rss_params(edev, &vport_update_params->rss_params,
1266f29ffdb6SMintz, Yuval 				     &vport_update_params->update_rss_flg);
1267f29ffdb6SMintz, Yuval 		rc = edev->ops->vport_update(edev->cdev, vport_update_params);
1268f29ffdb6SMintz, Yuval 		vfree(vport_update_params);
1269f29ffdb6SMintz, Yuval 	}
1270f29ffdb6SMintz, Yuval 	__qede_unlock(edev);
1271961acdeaSSudarsana Reddy Kalluru 
1272f29ffdb6SMintz, Yuval 	return rc;
1273961acdeaSSudarsana Reddy Kalluru }
1274961acdeaSSudarsana Reddy Kalluru 
1275961acdeaSSudarsana Reddy Kalluru static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
1276961acdeaSSudarsana Reddy Kalluru {
1277961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
12783f2a2b8bSChopra, Manish 	int rc;
1279961acdeaSSudarsana Reddy Kalluru 
1280961acdeaSSudarsana Reddy Kalluru 	switch (info->cmd) {
1281961acdeaSSudarsana Reddy Kalluru 	case ETHTOOL_SRXFH:
12823f2a2b8bSChopra, Manish 		rc = qede_set_rss_flags(edev, info);
12833f2a2b8bSChopra, Manish 		break;
12843f2a2b8bSChopra, Manish 	case ETHTOOL_SRXCLSRLINS:
12853f2a2b8bSChopra, Manish 		rc = qede_add_cls_rule(edev, info);
12863f2a2b8bSChopra, Manish 		break;
12873f2a2b8bSChopra, Manish 	case ETHTOOL_SRXCLSRLDEL:
12882ce9c93eSManish Chopra 		rc = qede_delete_flow_filter(edev, info->fs.location);
12893f2a2b8bSChopra, Manish 		break;
1290961acdeaSSudarsana Reddy Kalluru 	default:
1291961acdeaSSudarsana Reddy Kalluru 		DP_INFO(edev, "Command parameters not supported\n");
12923f2a2b8bSChopra, Manish 		rc = -EOPNOTSUPP;
1293961acdeaSSudarsana Reddy Kalluru 	}
12943f2a2b8bSChopra, Manish 
12953f2a2b8bSChopra, Manish 	return rc;
1296961acdeaSSudarsana Reddy Kalluru }
1297961acdeaSSudarsana Reddy Kalluru 
1298961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_indir_size(struct net_device *dev)
1299961acdeaSSudarsana Reddy Kalluru {
1300961acdeaSSudarsana Reddy Kalluru 	return QED_RSS_IND_TABLE_SIZE;
1301961acdeaSSudarsana Reddy Kalluru }
1302961acdeaSSudarsana Reddy Kalluru 
1303961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_key_size(struct net_device *dev)
1304961acdeaSSudarsana Reddy Kalluru {
1305961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1306961acdeaSSudarsana Reddy Kalluru 
1307f29ffdb6SMintz, Yuval 	return sizeof(edev->rss_key);
1308961acdeaSSudarsana Reddy Kalluru }
1309961acdeaSSudarsana Reddy Kalluru 
1310961acdeaSSudarsana Reddy Kalluru static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
1311961acdeaSSudarsana Reddy Kalluru {
1312961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1313961acdeaSSudarsana Reddy Kalluru 	int i;
1314961acdeaSSudarsana Reddy Kalluru 
1315961acdeaSSudarsana Reddy Kalluru 	if (hfunc)
1316961acdeaSSudarsana Reddy Kalluru 		*hfunc = ETH_RSS_HASH_TOP;
1317961acdeaSSudarsana Reddy Kalluru 
1318961acdeaSSudarsana Reddy Kalluru 	if (!indir)
1319961acdeaSSudarsana Reddy Kalluru 		return 0;
1320961acdeaSSudarsana Reddy Kalluru 
1321961acdeaSSudarsana Reddy Kalluru 	for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1322f29ffdb6SMintz, Yuval 		indir[i] = edev->rss_ind_table[i];
1323961acdeaSSudarsana Reddy Kalluru 
1324961acdeaSSudarsana Reddy Kalluru 	if (key)
1325f29ffdb6SMintz, Yuval 		memcpy(key, edev->rss_key, qede_get_rxfh_key_size(dev));
1326961acdeaSSudarsana Reddy Kalluru 
1327961acdeaSSudarsana Reddy Kalluru 	return 0;
1328961acdeaSSudarsana Reddy Kalluru }
1329961acdeaSSudarsana Reddy Kalluru 
1330961acdeaSSudarsana Reddy Kalluru static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
1331961acdeaSSudarsana Reddy Kalluru 			 const u8 *key, const u8 hfunc)
1332961acdeaSSudarsana Reddy Kalluru {
1333f29ffdb6SMintz, Yuval 	struct qed_update_vport_params *vport_update_params;
1334961acdeaSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1335f29ffdb6SMintz, Yuval 	int i, rc = 0;
1336961acdeaSSudarsana Reddy Kalluru 
1337ba300ce3SSudarsana Reddy Kalluru 	if (edev->dev_info.common.num_hwfns > 1) {
1338ba300ce3SSudarsana Reddy Kalluru 		DP_INFO(edev,
1339ba300ce3SSudarsana Reddy Kalluru 			"RSS configuration is not supported for 100G devices\n");
1340ba300ce3SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1341ba300ce3SSudarsana Reddy Kalluru 	}
1342ba300ce3SSudarsana Reddy Kalluru 
1343961acdeaSSudarsana Reddy Kalluru 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
1344961acdeaSSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1345961acdeaSSudarsana Reddy Kalluru 
1346961acdeaSSudarsana Reddy Kalluru 	if (!indir && !key)
1347961acdeaSSudarsana Reddy Kalluru 		return 0;
1348961acdeaSSudarsana Reddy Kalluru 
1349961acdeaSSudarsana Reddy Kalluru 	if (indir) {
1350961acdeaSSudarsana Reddy Kalluru 		for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
1351f29ffdb6SMintz, Yuval 			edev->rss_ind_table[i] = indir[i];
1352961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
1353961acdeaSSudarsana Reddy Kalluru 	}
1354961acdeaSSudarsana Reddy Kalluru 
1355961acdeaSSudarsana Reddy Kalluru 	if (key) {
1356f29ffdb6SMintz, Yuval 		memcpy(&edev->rss_key, key, qede_get_rxfh_key_size(dev));
1357961acdeaSSudarsana Reddy Kalluru 		edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
1358961acdeaSSudarsana Reddy Kalluru 	}
1359961acdeaSSudarsana Reddy Kalluru 
1360f29ffdb6SMintz, Yuval 	__qede_lock(edev);
1361f29ffdb6SMintz, Yuval 	if (edev->state == QEDE_STATE_OPEN) {
1362f29ffdb6SMintz, Yuval 		vport_update_params = vzalloc(sizeof(*vport_update_params));
1363f29ffdb6SMintz, Yuval 		if (!vport_update_params) {
1364f29ffdb6SMintz, Yuval 			__qede_unlock(edev);
1365f29ffdb6SMintz, Yuval 			return -ENOMEM;
1366961acdeaSSudarsana Reddy Kalluru 		}
1367f29ffdb6SMintz, Yuval 		qede_fill_rss_params(edev, &vport_update_params->rss_params,
1368f29ffdb6SMintz, Yuval 				     &vport_update_params->update_rss_flg);
1369f29ffdb6SMintz, Yuval 		rc = edev->ops->vport_update(edev->cdev, vport_update_params);
1370f29ffdb6SMintz, Yuval 		vfree(vport_update_params);
1371f29ffdb6SMintz, Yuval 	}
1372f29ffdb6SMintz, Yuval 	__qede_unlock(edev);
1373961acdeaSSudarsana Reddy Kalluru 
1374f29ffdb6SMintz, Yuval 	return rc;
1375961acdeaSSudarsana Reddy Kalluru }
1376961acdeaSSudarsana Reddy Kalluru 
137716f46bf0SSudarsana Reddy Kalluru /* This function enables the interrupt generation and the NAPI on the device */
137816f46bf0SSudarsana Reddy Kalluru static void qede_netif_start(struct qede_dev *edev)
137916f46bf0SSudarsana Reddy Kalluru {
138016f46bf0SSudarsana Reddy Kalluru 	int i;
138116f46bf0SSudarsana Reddy Kalluru 
138216f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev))
138316f46bf0SSudarsana Reddy Kalluru 		return;
138416f46bf0SSudarsana Reddy Kalluru 
13859a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
138616f46bf0SSudarsana Reddy Kalluru 		/* Update and reenable interrupts */
138716f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1);
138816f46bf0SSudarsana Reddy Kalluru 		napi_enable(&edev->fp_array[i].napi);
138916f46bf0SSudarsana Reddy Kalluru 	}
139016f46bf0SSudarsana Reddy Kalluru }
139116f46bf0SSudarsana Reddy Kalluru 
139216f46bf0SSudarsana Reddy Kalluru /* This function disables the NAPI and the interrupt generation on the device */
139316f46bf0SSudarsana Reddy Kalluru static void qede_netif_stop(struct qede_dev *edev)
139416f46bf0SSudarsana Reddy Kalluru {
139516f46bf0SSudarsana Reddy Kalluru 	int i;
139616f46bf0SSudarsana Reddy Kalluru 
13979a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
139816f46bf0SSudarsana Reddy Kalluru 		napi_disable(&edev->fp_array[i].napi);
139916f46bf0SSudarsana Reddy Kalluru 		/* Disable interrupts */
140016f46bf0SSudarsana Reddy Kalluru 		qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0);
140116f46bf0SSudarsana Reddy Kalluru 	}
140216f46bf0SSudarsana Reddy Kalluru }
140316f46bf0SSudarsana Reddy Kalluru 
140416f46bf0SSudarsana Reddy Kalluru static int qede_selftest_transmit_traffic(struct qede_dev *edev,
140516f46bf0SSudarsana Reddy Kalluru 					  struct sk_buff *skb)
140616f46bf0SSudarsana Reddy Kalluru {
14079a4d7e86SSudarsana Reddy Kalluru 	struct qede_tx_queue *txq = NULL;
140816f46bf0SSudarsana Reddy Kalluru 	struct eth_tx_1st_bd *first_bd;
140916f46bf0SSudarsana Reddy Kalluru 	dma_addr_t mapping;
141048848a06SManish Chopra 	int i, idx;
141148848a06SManish Chopra 	u16 val;
141216f46bf0SSudarsana Reddy Kalluru 
14139a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
14145e7baf0fSManish Chopra 		struct qede_fastpath *fp = &edev->fp_array[i];
14155e7baf0fSManish Chopra 
14165e7baf0fSManish Chopra 		if (fp->type & QEDE_FASTPATH_TX) {
14175e7baf0fSManish Chopra 			txq = QEDE_FP_TC0_TXQ(fp);
14189a4d7e86SSudarsana Reddy Kalluru 			break;
14199a4d7e86SSudarsana Reddy Kalluru 		}
14209a4d7e86SSudarsana Reddy Kalluru 	}
14219a4d7e86SSudarsana Reddy Kalluru 
14229a4d7e86SSudarsana Reddy Kalluru 	if (!txq) {
14239a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx path is not available\n");
14249a4d7e86SSudarsana Reddy Kalluru 		return -1;
14259a4d7e86SSudarsana Reddy Kalluru 	}
14269a4d7e86SSudarsana Reddy Kalluru 
142716f46bf0SSudarsana Reddy Kalluru 	/* Fill the entry in the SW ring and the BDs in the FW ring */
14285a052d62SSudarsana Reddy Kalluru 	idx = txq->sw_tx_prod;
1429cb6aeb07SMintz, Yuval 	txq->sw_tx_ring.skbs[idx].skb = skb;
143016f46bf0SSudarsana Reddy Kalluru 	first_bd = qed_chain_produce(&txq->tx_pbl);
143116f46bf0SSudarsana Reddy Kalluru 	memset(first_bd, 0, sizeof(*first_bd));
143216f46bf0SSudarsana Reddy Kalluru 	val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT;
143316f46bf0SSudarsana Reddy Kalluru 	first_bd->data.bd_flags.bitfields = val;
1434351a4dedSYuval Mintz 	val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK;
143548848a06SManish Chopra 	val = val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT;
143648848a06SManish Chopra 	first_bd->data.bitfields |= cpu_to_le16(val);
143716f46bf0SSudarsana Reddy Kalluru 
143816f46bf0SSudarsana Reddy Kalluru 	/* Map skb linear data for DMA and set in the first BD */
143916f46bf0SSudarsana Reddy Kalluru 	mapping = dma_map_single(&edev->pdev->dev, skb->data,
144016f46bf0SSudarsana Reddy Kalluru 				 skb_headlen(skb), DMA_TO_DEVICE);
144116f46bf0SSudarsana Reddy Kalluru 	if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
144216f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "SKB mapping failed\n");
144316f46bf0SSudarsana Reddy Kalluru 		return -ENOMEM;
144416f46bf0SSudarsana Reddy Kalluru 	}
144516f46bf0SSudarsana Reddy Kalluru 	BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb));
144616f46bf0SSudarsana Reddy Kalluru 
144716f46bf0SSudarsana Reddy Kalluru 	/* update the first BD with the actual num BDs */
144816f46bf0SSudarsana Reddy Kalluru 	first_bd->data.nbds = 1;
14495a052d62SSudarsana Reddy Kalluru 	txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers;
145016f46bf0SSudarsana Reddy Kalluru 	/* 'next page' entries are counted in the producer value */
145148848a06SManish Chopra 	val = qed_chain_get_prod_idx(&txq->tx_pbl);
145248848a06SManish Chopra 	txq->tx_db.data.bd_prod = cpu_to_le16(val);
145316f46bf0SSudarsana Reddy Kalluru 
145416f46bf0SSudarsana Reddy Kalluru 	/* wmb makes sure that the BDs data is updated before updating the
145516f46bf0SSudarsana Reddy Kalluru 	 * producer, otherwise FW may read old data from the BDs.
145616f46bf0SSudarsana Reddy Kalluru 	 */
145716f46bf0SSudarsana Reddy Kalluru 	wmb();
145816f46bf0SSudarsana Reddy Kalluru 	barrier();
145916f46bf0SSudarsana Reddy Kalluru 	writel(txq->tx_db.raw, txq->doorbell_addr);
146016f46bf0SSudarsana Reddy Kalluru 
146116f46bf0SSudarsana Reddy Kalluru 	/* mmiowb is needed to synchronize doorbell writes from more than one
146216f46bf0SSudarsana Reddy Kalluru 	 * processor. It guarantees that the write arrives to the device before
146316f46bf0SSudarsana Reddy Kalluru 	 * the queue lock is released and another start_xmit is called (possibly
146416f46bf0SSudarsana Reddy Kalluru 	 * on another CPU). Without this barrier, the next doorbell can bypass
146516f46bf0SSudarsana Reddy Kalluru 	 * this doorbell. This is applicable to IA64/Altix systems.
146616f46bf0SSudarsana Reddy Kalluru 	 */
146716f46bf0SSudarsana Reddy Kalluru 	mmiowb();
146816f46bf0SSudarsana Reddy Kalluru 
146916f46bf0SSudarsana Reddy Kalluru 	for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
147016f46bf0SSudarsana Reddy Kalluru 		if (qede_txq_has_work(txq))
147116f46bf0SSudarsana Reddy Kalluru 			break;
147216f46bf0SSudarsana Reddy Kalluru 		usleep_range(100, 200);
147316f46bf0SSudarsana Reddy Kalluru 	}
147416f46bf0SSudarsana Reddy Kalluru 
147516f46bf0SSudarsana Reddy Kalluru 	if (!qede_txq_has_work(txq)) {
147616f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Tx completion didn't happen\n");
147716f46bf0SSudarsana Reddy Kalluru 		return -1;
147816f46bf0SSudarsana Reddy Kalluru 	}
147916f46bf0SSudarsana Reddy Kalluru 
148016f46bf0SSudarsana Reddy Kalluru 	first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
1481fabd545cSManish Chopra 	dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
148216f46bf0SSudarsana Reddy Kalluru 			 BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
14835a052d62SSudarsana Reddy Kalluru 	txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers;
1484cb6aeb07SMintz, Yuval 	txq->sw_tx_ring.skbs[idx].skb = NULL;
148516f46bf0SSudarsana Reddy Kalluru 
148616f46bf0SSudarsana Reddy Kalluru 	return 0;
148716f46bf0SSudarsana Reddy Kalluru }
148816f46bf0SSudarsana Reddy Kalluru 
148916f46bf0SSudarsana Reddy Kalluru static int qede_selftest_receive_traffic(struct qede_dev *edev)
149016f46bf0SSudarsana Reddy Kalluru {
149116f46bf0SSudarsana Reddy Kalluru 	u16 hw_comp_cons, sw_comp_cons, sw_rx_index, len;
149216f46bf0SSudarsana Reddy Kalluru 	struct eth_fast_path_rx_reg_cqe *fp_cqe;
14939a4d7e86SSudarsana Reddy Kalluru 	struct qede_rx_queue *rxq = NULL;
149416f46bf0SSudarsana Reddy Kalluru 	struct sw_rx_data *sw_rx_data;
149516f46bf0SSudarsana Reddy Kalluru 	union eth_rx_cqe *cqe;
1496afe981d6SSudarsana Reddy Kalluru 	int i, iter, rc = 0;
149716f46bf0SSudarsana Reddy Kalluru 	u8 *data_ptr;
149816f46bf0SSudarsana Reddy Kalluru 
14999a4d7e86SSudarsana Reddy Kalluru 	for_each_queue(i) {
15009a4d7e86SSudarsana Reddy Kalluru 		if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
15019a4d7e86SSudarsana Reddy Kalluru 			rxq = edev->fp_array[i].rxq;
15029a4d7e86SSudarsana Reddy Kalluru 			break;
15039a4d7e86SSudarsana Reddy Kalluru 		}
15049a4d7e86SSudarsana Reddy Kalluru 	}
15059a4d7e86SSudarsana Reddy Kalluru 
15069a4d7e86SSudarsana Reddy Kalluru 	if (!rxq) {
15079a4d7e86SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Rx path is not available\n");
15089a4d7e86SSudarsana Reddy Kalluru 		return -1;
15099a4d7e86SSudarsana Reddy Kalluru 	}
15109a4d7e86SSudarsana Reddy Kalluru 
151116f46bf0SSudarsana Reddy Kalluru 	/* The packet is expected to receive on rx-queue 0 even though RSS is
151216f46bf0SSudarsana Reddy Kalluru 	 * enabled. This is because the queue 0 is configured as the default
151316f46bf0SSudarsana Reddy Kalluru 	 * queue and that the loopback traffic is not IP.
151416f46bf0SSudarsana Reddy Kalluru 	 */
1515afe981d6SSudarsana Reddy Kalluru 	for (iter = 0; iter < QEDE_SELFTEST_POLL_COUNT; iter++) {
151616f46bf0SSudarsana Reddy Kalluru 		if (!qede_has_rx_work(rxq)) {
1517837d4eb6SSudarsana Reddy Kalluru 			usleep_range(100, 200);
1518837d4eb6SSudarsana Reddy Kalluru 			continue;
151916f46bf0SSudarsana Reddy Kalluru 		}
152016f46bf0SSudarsana Reddy Kalluru 
152116f46bf0SSudarsana Reddy Kalluru 		hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
152216f46bf0SSudarsana Reddy Kalluru 		sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
152316f46bf0SSudarsana Reddy Kalluru 
1524837d4eb6SSudarsana Reddy Kalluru 		/* Memory barrier to prevent the CPU from doing speculative
1525837d4eb6SSudarsana Reddy Kalluru 		 * reads of CQE/BD before reading hw_comp_cons. If the CQE is
1526837d4eb6SSudarsana Reddy Kalluru 		 * read before it is written by FW, then FW writes CQE and SB,
1527837d4eb6SSudarsana Reddy Kalluru 		 * and then the CPU reads the hw_comp_cons, it will use an old
1528837d4eb6SSudarsana Reddy Kalluru 		 * CQE.
152916f46bf0SSudarsana Reddy Kalluru 		 */
153016f46bf0SSudarsana Reddy Kalluru 		rmb();
153116f46bf0SSudarsana Reddy Kalluru 
153216f46bf0SSudarsana Reddy Kalluru 		/* Get the CQE from the completion ring */
153316f46bf0SSudarsana Reddy Kalluru 		cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
153416f46bf0SSudarsana Reddy Kalluru 
153516f46bf0SSudarsana Reddy Kalluru 		/* Get the data from the SW ring */
153616f46bf0SSudarsana Reddy Kalluru 		sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
153716f46bf0SSudarsana Reddy Kalluru 		sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
153816f46bf0SSudarsana Reddy Kalluru 		fp_cqe = &cqe->fast_path_regular;
153916f46bf0SSudarsana Reddy Kalluru 		len =  le16_to_cpu(fp_cqe->len_on_first_bd);
154016f46bf0SSudarsana Reddy Kalluru 		data_ptr = (u8 *)(page_address(sw_rx_data->data) +
1541837d4eb6SSudarsana Reddy Kalluru 				  fp_cqe->placement_offset +
15428a863397SManish Chopra 				  sw_rx_data->page_offset +
15438a863397SManish Chopra 				  rxq->rx_headroom);
1544837d4eb6SSudarsana Reddy Kalluru 		if (ether_addr_equal(data_ptr,  edev->ndev->dev_addr) &&
1545837d4eb6SSudarsana Reddy Kalluru 		    ether_addr_equal(data_ptr + ETH_ALEN,
1546837d4eb6SSudarsana Reddy Kalluru 				     edev->ndev->dev_addr)) {
154716f46bf0SSudarsana Reddy Kalluru 			for (i = ETH_HLEN; i < len; i++)
154816f46bf0SSudarsana Reddy Kalluru 				if (data_ptr[i] != (unsigned char)(i & 0xff)) {
1549837d4eb6SSudarsana Reddy Kalluru 					rc = -1;
1550837d4eb6SSudarsana Reddy Kalluru 					break;
155116f46bf0SSudarsana Reddy Kalluru 				}
155216f46bf0SSudarsana Reddy Kalluru 
15539eb22357SMintz, Yuval 			qede_recycle_rx_bd_ring(rxq, 1);
1554837d4eb6SSudarsana Reddy Kalluru 			qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1555837d4eb6SSudarsana Reddy Kalluru 			break;
1556837d4eb6SSudarsana Reddy Kalluru 		}
155716f46bf0SSudarsana Reddy Kalluru 
1558837d4eb6SSudarsana Reddy Kalluru 		DP_INFO(edev, "Not the transmitted packet\n");
15599eb22357SMintz, Yuval 		qede_recycle_rx_bd_ring(rxq, 1);
1560837d4eb6SSudarsana Reddy Kalluru 		qed_chain_recycle_consumed(&rxq->rx_comp_ring);
1561837d4eb6SSudarsana Reddy Kalluru 	}
1562837d4eb6SSudarsana Reddy Kalluru 
1563afe981d6SSudarsana Reddy Kalluru 	if (iter == QEDE_SELFTEST_POLL_COUNT) {
1564837d4eb6SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Failed to receive the traffic\n");
1565837d4eb6SSudarsana Reddy Kalluru 		return -1;
1566837d4eb6SSudarsana Reddy Kalluru 	}
1567837d4eb6SSudarsana Reddy Kalluru 
1568837d4eb6SSudarsana Reddy Kalluru 	qede_update_rx_prod(edev, rxq);
1569837d4eb6SSudarsana Reddy Kalluru 
1570837d4eb6SSudarsana Reddy Kalluru 	return rc;
157116f46bf0SSudarsana Reddy Kalluru }
157216f46bf0SSudarsana Reddy Kalluru 
157316f46bf0SSudarsana Reddy Kalluru static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode)
157416f46bf0SSudarsana Reddy Kalluru {
157516f46bf0SSudarsana Reddy Kalluru 	struct qed_link_params link_params;
157616f46bf0SSudarsana Reddy Kalluru 	struct sk_buff *skb = NULL;
157716f46bf0SSudarsana Reddy Kalluru 	int rc = 0, i;
157816f46bf0SSudarsana Reddy Kalluru 	u32 pkt_size;
157916f46bf0SSudarsana Reddy Kalluru 	u8 *packet;
158016f46bf0SSudarsana Reddy Kalluru 
158116f46bf0SSudarsana Reddy Kalluru 	if (!netif_running(edev->ndev)) {
158216f46bf0SSudarsana Reddy Kalluru 		DP_NOTICE(edev, "Interface is down\n");
158316f46bf0SSudarsana Reddy Kalluru 		return -EINVAL;
158416f46bf0SSudarsana Reddy Kalluru 	}
158516f46bf0SSudarsana Reddy Kalluru 
158616f46bf0SSudarsana Reddy Kalluru 	qede_netif_stop(edev);
158716f46bf0SSudarsana Reddy Kalluru 
158816f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Loopback mode */
158916f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
159016f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
159116f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
159216f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = loopback_mode;
159316f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
159416f46bf0SSudarsana Reddy Kalluru 
159516f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
159616f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
159716f46bf0SSudarsana Reddy Kalluru 
159816f46bf0SSudarsana Reddy Kalluru 	/* prepare the loopback packet */
159916f46bf0SSudarsana Reddy Kalluru 	pkt_size = edev->ndev->mtu + ETH_HLEN;
160016f46bf0SSudarsana Reddy Kalluru 
160116f46bf0SSudarsana Reddy Kalluru 	skb = netdev_alloc_skb(edev->ndev, pkt_size);
160216f46bf0SSudarsana Reddy Kalluru 	if (!skb) {
160316f46bf0SSudarsana Reddy Kalluru 		DP_INFO(edev, "Can't allocate skb\n");
160416f46bf0SSudarsana Reddy Kalluru 		rc = -ENOMEM;
160516f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
160616f46bf0SSudarsana Reddy Kalluru 	}
160716f46bf0SSudarsana Reddy Kalluru 	packet = skb_put(skb, pkt_size);
160816f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet, edev->ndev->dev_addr);
160916f46bf0SSudarsana Reddy Kalluru 	ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr);
161016f46bf0SSudarsana Reddy Kalluru 	memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN)));
161116f46bf0SSudarsana Reddy Kalluru 	for (i = ETH_HLEN; i < pkt_size; i++)
161216f46bf0SSudarsana Reddy Kalluru 		packet[i] = (unsigned char)(i & 0xff);
161316f46bf0SSudarsana Reddy Kalluru 
161416f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_transmit_traffic(edev, skb);
161516f46bf0SSudarsana Reddy Kalluru 	if (rc)
161616f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
161716f46bf0SSudarsana Reddy Kalluru 
161816f46bf0SSudarsana Reddy Kalluru 	rc = qede_selftest_receive_traffic(edev);
161916f46bf0SSudarsana Reddy Kalluru 	if (rc)
162016f46bf0SSudarsana Reddy Kalluru 		goto test_loopback_exit;
162116f46bf0SSudarsana Reddy Kalluru 
162216f46bf0SSudarsana Reddy Kalluru 	DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n");
162316f46bf0SSudarsana Reddy Kalluru 
162416f46bf0SSudarsana Reddy Kalluru test_loopback_exit:
162516f46bf0SSudarsana Reddy Kalluru 	dev_kfree_skb(skb);
162616f46bf0SSudarsana Reddy Kalluru 
162716f46bf0SSudarsana Reddy Kalluru 	/* Bring up the link in Normal mode */
162816f46bf0SSudarsana Reddy Kalluru 	memset(&link_params, 0, sizeof(link_params));
162916f46bf0SSudarsana Reddy Kalluru 	link_params.link_up = true;
163016f46bf0SSudarsana Reddy Kalluru 	link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE;
163116f46bf0SSudarsana Reddy Kalluru 	link_params.loopback_mode = QED_LINK_LOOPBACK_NONE;
163216f46bf0SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &link_params);
163316f46bf0SSudarsana Reddy Kalluru 
163416f46bf0SSudarsana Reddy Kalluru 	/* Wait for loopback configuration to apply */
163516f46bf0SSudarsana Reddy Kalluru 	msleep_interruptible(500);
163616f46bf0SSudarsana Reddy Kalluru 
163716f46bf0SSudarsana Reddy Kalluru 	qede_netif_start(edev);
163816f46bf0SSudarsana Reddy Kalluru 
163916f46bf0SSudarsana Reddy Kalluru 	return rc;
164016f46bf0SSudarsana Reddy Kalluru }
164116f46bf0SSudarsana Reddy Kalluru 
16423044a02eSSudarsana Reddy Kalluru static void qede_self_test(struct net_device *dev,
16433044a02eSSudarsana Reddy Kalluru 			   struct ethtool_test *etest, u64 *buf)
16443044a02eSSudarsana Reddy Kalluru {
16453044a02eSSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
16463044a02eSSudarsana Reddy Kalluru 
16473044a02eSSudarsana Reddy Kalluru 	DP_VERBOSE(edev, QED_MSG_DEBUG,
16483044a02eSSudarsana Reddy Kalluru 		   "Self-test command parameters: offline = %d, external_lb = %d\n",
16493044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_OFFLINE),
16503044a02eSSudarsana Reddy Kalluru 		   (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2);
16513044a02eSSudarsana Reddy Kalluru 
16523044a02eSSudarsana Reddy Kalluru 	memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX);
16533044a02eSSudarsana Reddy Kalluru 
165416f46bf0SSudarsana Reddy Kalluru 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
165516f46bf0SSudarsana Reddy Kalluru 		if (qede_selftest_run_loopback(edev,
165616f46bf0SSudarsana Reddy Kalluru 					       QED_LINK_LOOPBACK_INT_PHY)) {
165716f46bf0SSudarsana Reddy Kalluru 			buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1;
165816f46bf0SSudarsana Reddy Kalluru 			etest->flags |= ETH_TEST_FL_FAILED;
165916f46bf0SSudarsana Reddy Kalluru 		}
166016f46bf0SSudarsana Reddy Kalluru 	}
166116f46bf0SSudarsana Reddy Kalluru 
16623044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) {
16633044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1;
16643044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
16653044a02eSSudarsana Reddy Kalluru 	}
16663044a02eSSudarsana Reddy Kalluru 
16673044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_memory(edev->cdev)) {
16683044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_MEMORY_TEST] = 1;
16693044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
16703044a02eSSudarsana Reddy Kalluru 	}
16713044a02eSSudarsana Reddy Kalluru 
16723044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_register(edev->cdev)) {
16733044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_REGISTER_TEST] = 1;
16743044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
16753044a02eSSudarsana Reddy Kalluru 	}
16763044a02eSSudarsana Reddy Kalluru 
16773044a02eSSudarsana Reddy Kalluru 	if (edev->ops->common->selftest->selftest_clock(edev->cdev)) {
16783044a02eSSudarsana Reddy Kalluru 		buf[QEDE_ETHTOOL_CLOCK_TEST] = 1;
16793044a02eSSudarsana Reddy Kalluru 		etest->flags |= ETH_TEST_FL_FAILED;
16803044a02eSSudarsana Reddy Kalluru 	}
16817a4b21b7SMintz, Yuval 
16827a4b21b7SMintz, Yuval 	if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) {
16837a4b21b7SMintz, Yuval 		buf[QEDE_ETHTOOL_NVRAM_TEST] = 1;
16847a4b21b7SMintz, Yuval 		etest->flags |= ETH_TEST_FL_FAILED;
16857a4b21b7SMintz, Yuval 	}
16863044a02eSSudarsana Reddy Kalluru }
16873044a02eSSudarsana Reddy Kalluru 
16883d789994SManish Chopra static int qede_set_tunable(struct net_device *dev,
16893d789994SManish Chopra 			    const struct ethtool_tunable *tuna,
16903d789994SManish Chopra 			    const void *data)
16913d789994SManish Chopra {
16923d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
16933d789994SManish Chopra 	u32 val;
16943d789994SManish Chopra 
16953d789994SManish Chopra 	switch (tuna->id) {
16963d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
16973d789994SManish Chopra 		val = *(u32 *)data;
16983d789994SManish Chopra 		if (val < QEDE_MIN_PKT_LEN || val > QEDE_RX_HDR_SIZE) {
16993d789994SManish Chopra 			DP_VERBOSE(edev, QED_MSG_DEBUG,
17003d789994SManish Chopra 				   "Invalid rx copy break value, range is [%u, %u]",
17013d789994SManish Chopra 				   QEDE_MIN_PKT_LEN, QEDE_RX_HDR_SIZE);
17023d789994SManish Chopra 			return -EINVAL;
17033d789994SManish Chopra 		}
17043d789994SManish Chopra 
17053d789994SManish Chopra 		edev->rx_copybreak = *(u32 *)data;
17063d789994SManish Chopra 		break;
17073d789994SManish Chopra 	default:
17083d789994SManish Chopra 		return -EOPNOTSUPP;
17093d789994SManish Chopra 	}
17103d789994SManish Chopra 
17113d789994SManish Chopra 	return 0;
17123d789994SManish Chopra }
17133d789994SManish Chopra 
17143d789994SManish Chopra static int qede_get_tunable(struct net_device *dev,
17153d789994SManish Chopra 			    const struct ethtool_tunable *tuna, void *data)
17163d789994SManish Chopra {
17173d789994SManish Chopra 	struct qede_dev *edev = netdev_priv(dev);
17183d789994SManish Chopra 
17193d789994SManish Chopra 	switch (tuna->id) {
17203d789994SManish Chopra 	case ETHTOOL_RX_COPYBREAK:
17213d789994SManish Chopra 		*(u32 *)data = edev->rx_copybreak;
17223d789994SManish Chopra 		break;
17233d789994SManish Chopra 	default:
17243d789994SManish Chopra 		return -EOPNOTSUPP;
17253d789994SManish Chopra 	}
17263d789994SManish Chopra 
17273d789994SManish Chopra 	return 0;
17283d789994SManish Chopra }
17293d789994SManish Chopra 
1730c3dc48f7SSudarsana Reddy Kalluru static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata)
1731c3dc48f7SSudarsana Reddy Kalluru {
1732c3dc48f7SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1733c3dc48f7SSudarsana Reddy Kalluru 	struct qed_link_output current_link;
1734c3dc48f7SSudarsana Reddy Kalluru 
1735c3dc48f7SSudarsana Reddy Kalluru 	memset(&current_link, 0, sizeof(current_link));
1736c3dc48f7SSudarsana Reddy Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
1737c3dc48f7SSudarsana Reddy Kalluru 
1738c3dc48f7SSudarsana Reddy Kalluru 	if (!current_link.eee_supported) {
1739c3dc48f7SSudarsana Reddy Kalluru 		DP_INFO(edev, "EEE is not supported\n");
1740c3dc48f7SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1741c3dc48f7SSudarsana Reddy Kalluru 	}
1742c3dc48f7SSudarsana Reddy Kalluru 
1743c3dc48f7SSudarsana Reddy Kalluru 	if (current_link.eee.adv_caps & QED_EEE_1G_ADV)
1744c3dc48f7SSudarsana Reddy Kalluru 		edata->advertised = ADVERTISED_1000baseT_Full;
1745c3dc48f7SSudarsana Reddy Kalluru 	if (current_link.eee.adv_caps & QED_EEE_10G_ADV)
1746c3dc48f7SSudarsana Reddy Kalluru 		edata->advertised |= ADVERTISED_10000baseT_Full;
1747c3dc48f7SSudarsana Reddy Kalluru 	if (current_link.sup_caps & QED_EEE_1G_ADV)
1748c3dc48f7SSudarsana Reddy Kalluru 		edata->supported = ADVERTISED_1000baseT_Full;
1749c3dc48f7SSudarsana Reddy Kalluru 	if (current_link.sup_caps & QED_EEE_10G_ADV)
1750c3dc48f7SSudarsana Reddy Kalluru 		edata->supported |= ADVERTISED_10000baseT_Full;
1751c3dc48f7SSudarsana Reddy Kalluru 	if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV)
1752c3dc48f7SSudarsana Reddy Kalluru 		edata->lp_advertised = ADVERTISED_1000baseT_Full;
1753c3dc48f7SSudarsana Reddy Kalluru 	if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV)
1754c3dc48f7SSudarsana Reddy Kalluru 		edata->lp_advertised |= ADVERTISED_10000baseT_Full;
1755c3dc48f7SSudarsana Reddy Kalluru 
1756c3dc48f7SSudarsana Reddy Kalluru 	edata->tx_lpi_timer = current_link.eee.tx_lpi_timer;
1757c3dc48f7SSudarsana Reddy Kalluru 	edata->eee_enabled = current_link.eee.enable;
1758c3dc48f7SSudarsana Reddy Kalluru 	edata->tx_lpi_enabled = current_link.eee.tx_lpi_enable;
1759c3dc48f7SSudarsana Reddy Kalluru 	edata->eee_active = current_link.eee_active;
1760c3dc48f7SSudarsana Reddy Kalluru 
1761c3dc48f7SSudarsana Reddy Kalluru 	return 0;
1762c3dc48f7SSudarsana Reddy Kalluru }
1763c3dc48f7SSudarsana Reddy Kalluru 
1764c3dc48f7SSudarsana Reddy Kalluru static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata)
1765c3dc48f7SSudarsana Reddy Kalluru {
1766c3dc48f7SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
1767c3dc48f7SSudarsana Reddy Kalluru 	struct qed_link_output current_link;
1768c3dc48f7SSudarsana Reddy Kalluru 	struct qed_link_params params;
1769c3dc48f7SSudarsana Reddy Kalluru 
1770c3dc48f7SSudarsana Reddy Kalluru 	if (!edev->ops->common->can_link_change(edev->cdev)) {
1771c3dc48f7SSudarsana Reddy Kalluru 		DP_INFO(edev, "Link settings are not allowed to be changed\n");
1772c3dc48f7SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1773c3dc48f7SSudarsana Reddy Kalluru 	}
1774c3dc48f7SSudarsana Reddy Kalluru 
1775c3dc48f7SSudarsana Reddy Kalluru 	memset(&current_link, 0, sizeof(current_link));
1776c3dc48f7SSudarsana Reddy Kalluru 	edev->ops->common->get_link(edev->cdev, &current_link);
1777c3dc48f7SSudarsana Reddy Kalluru 
1778c3dc48f7SSudarsana Reddy Kalluru 	if (!current_link.eee_supported) {
1779c3dc48f7SSudarsana Reddy Kalluru 		DP_INFO(edev, "EEE is not supported\n");
1780c3dc48f7SSudarsana Reddy Kalluru 		return -EOPNOTSUPP;
1781c3dc48f7SSudarsana Reddy Kalluru 	}
1782c3dc48f7SSudarsana Reddy Kalluru 
1783c3dc48f7SSudarsana Reddy Kalluru 	memset(&params, 0, sizeof(params));
1784c3dc48f7SSudarsana Reddy Kalluru 	params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG;
1785c3dc48f7SSudarsana Reddy Kalluru 
1786c3dc48f7SSudarsana Reddy Kalluru 	if (!(edata->advertised & (ADVERTISED_1000baseT_Full |
1787c3dc48f7SSudarsana Reddy Kalluru 				   ADVERTISED_10000baseT_Full)) ||
1788c3dc48f7SSudarsana Reddy Kalluru 	    ((edata->advertised & (ADVERTISED_1000baseT_Full |
1789c3dc48f7SSudarsana Reddy Kalluru 				   ADVERTISED_10000baseT_Full)) !=
1790c3dc48f7SSudarsana Reddy Kalluru 	     edata->advertised)) {
1791c3dc48f7SSudarsana Reddy Kalluru 		DP_VERBOSE(edev, QED_MSG_DEBUG,
1792c3dc48f7SSudarsana Reddy Kalluru 			   "Invalid advertised capabilities %d\n",
1793c3dc48f7SSudarsana Reddy Kalluru 			   edata->advertised);
1794c3dc48f7SSudarsana Reddy Kalluru 		return -EINVAL;
1795c3dc48f7SSudarsana Reddy Kalluru 	}
1796c3dc48f7SSudarsana Reddy Kalluru 
1797c3dc48f7SSudarsana Reddy Kalluru 	if (edata->advertised & ADVERTISED_1000baseT_Full)
1798c3dc48f7SSudarsana Reddy Kalluru 		params.eee.adv_caps = QED_EEE_1G_ADV;
1799c3dc48f7SSudarsana Reddy Kalluru 	if (edata->advertised & ADVERTISED_10000baseT_Full)
1800c3dc48f7SSudarsana Reddy Kalluru 		params.eee.adv_caps |= QED_EEE_10G_ADV;
1801c3dc48f7SSudarsana Reddy Kalluru 	params.eee.enable = edata->eee_enabled;
1802c3dc48f7SSudarsana Reddy Kalluru 	params.eee.tx_lpi_enable = edata->tx_lpi_enabled;
1803c3dc48f7SSudarsana Reddy Kalluru 	params.eee.tx_lpi_timer = edata->tx_lpi_timer;
1804c3dc48f7SSudarsana Reddy Kalluru 
1805c3dc48f7SSudarsana Reddy Kalluru 	params.link_up = true;
1806c3dc48f7SSudarsana Reddy Kalluru 	edev->ops->common->set_link(edev->cdev, &params);
1807c3dc48f7SSudarsana Reddy Kalluru 
1808c3dc48f7SSudarsana Reddy Kalluru 	return 0;
1809c3dc48f7SSudarsana Reddy Kalluru }
1810c3dc48f7SSudarsana Reddy Kalluru 
181197df0d65SSudarsana Reddy Kalluru static int qede_get_module_info(struct net_device *dev,
181297df0d65SSudarsana Reddy Kalluru 				struct ethtool_modinfo *modinfo)
181397df0d65SSudarsana Reddy Kalluru {
181497df0d65SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
181597df0d65SSudarsana Reddy Kalluru 	u8 buf[4];
181697df0d65SSudarsana Reddy Kalluru 	int rc;
181797df0d65SSudarsana Reddy Kalluru 
181897df0d65SSudarsana Reddy Kalluru 	/* Read first 4 bytes to find the sfp type */
181997df0d65SSudarsana Reddy Kalluru 	rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
182097df0d65SSudarsana Reddy Kalluru 						   QED_I2C_DEV_ADDR_A0, 0, 4);
182197df0d65SSudarsana Reddy Kalluru 	if (rc) {
182297df0d65SSudarsana Reddy Kalluru 		DP_ERR(edev, "Failed reading EEPROM data %d\n", rc);
182397df0d65SSudarsana Reddy Kalluru 		return rc;
182497df0d65SSudarsana Reddy Kalluru 	}
182597df0d65SSudarsana Reddy Kalluru 
182697df0d65SSudarsana Reddy Kalluru 	switch (buf[0]) {
182797df0d65SSudarsana Reddy Kalluru 	case 0x3: /* SFP, SFP+, SFP-28 */
182897df0d65SSudarsana Reddy Kalluru 		modinfo->type = ETH_MODULE_SFF_8472;
182997df0d65SSudarsana Reddy Kalluru 		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
183097df0d65SSudarsana Reddy Kalluru 		break;
183197df0d65SSudarsana Reddy Kalluru 	case 0xc: /* QSFP */
183297df0d65SSudarsana Reddy Kalluru 	case 0xd: /* QSFP+ */
183397df0d65SSudarsana Reddy Kalluru 		modinfo->type = ETH_MODULE_SFF_8436;
183497df0d65SSudarsana Reddy Kalluru 		modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
183597df0d65SSudarsana Reddy Kalluru 		break;
183697df0d65SSudarsana Reddy Kalluru 	case 0x11: /* QSFP-28 */
183797df0d65SSudarsana Reddy Kalluru 		modinfo->type = ETH_MODULE_SFF_8636;
183897df0d65SSudarsana Reddy Kalluru 		modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
183997df0d65SSudarsana Reddy Kalluru 		break;
184097df0d65SSudarsana Reddy Kalluru 	default:
184197df0d65SSudarsana Reddy Kalluru 		DP_ERR(edev, "Unknown transceiver type 0x%x\n", buf[0]);
184297df0d65SSudarsana Reddy Kalluru 		return -EINVAL;
184397df0d65SSudarsana Reddy Kalluru 	}
184497df0d65SSudarsana Reddy Kalluru 
184597df0d65SSudarsana Reddy Kalluru 	return 0;
184697df0d65SSudarsana Reddy Kalluru }
184797df0d65SSudarsana Reddy Kalluru 
184897df0d65SSudarsana Reddy Kalluru static int qede_get_module_eeprom(struct net_device *dev,
184997df0d65SSudarsana Reddy Kalluru 				  struct ethtool_eeprom *ee, u8 *data)
185097df0d65SSudarsana Reddy Kalluru {
185197df0d65SSudarsana Reddy Kalluru 	struct qede_dev *edev = netdev_priv(dev);
185297df0d65SSudarsana Reddy Kalluru 	u32 start_addr = ee->offset, size = 0;
185397df0d65SSudarsana Reddy Kalluru 	u8 *buf = data;
185497df0d65SSudarsana Reddy Kalluru 	int rc = 0;
185597df0d65SSudarsana Reddy Kalluru 
185697df0d65SSudarsana Reddy Kalluru 	/* Read A0 section */
185797df0d65SSudarsana Reddy Kalluru 	if (ee->offset < ETH_MODULE_SFF_8079_LEN) {
185897df0d65SSudarsana Reddy Kalluru 		/* Limit transfer size to the A0 section boundary */
185997df0d65SSudarsana Reddy Kalluru 		if (ee->offset + ee->len > ETH_MODULE_SFF_8079_LEN)
186097df0d65SSudarsana Reddy Kalluru 			size = ETH_MODULE_SFF_8079_LEN - ee->offset;
186197df0d65SSudarsana Reddy Kalluru 		else
186297df0d65SSudarsana Reddy Kalluru 			size = ee->len;
186397df0d65SSudarsana Reddy Kalluru 
186497df0d65SSudarsana Reddy Kalluru 		rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
186597df0d65SSudarsana Reddy Kalluru 							   QED_I2C_DEV_ADDR_A0,
186697df0d65SSudarsana Reddy Kalluru 							   start_addr, size);
186797df0d65SSudarsana Reddy Kalluru 		if (rc) {
186897df0d65SSudarsana Reddy Kalluru 			DP_ERR(edev, "Failed reading A0 section  %d\n", rc);
186997df0d65SSudarsana Reddy Kalluru 			return rc;
187097df0d65SSudarsana Reddy Kalluru 		}
187197df0d65SSudarsana Reddy Kalluru 
187297df0d65SSudarsana Reddy Kalluru 		buf += size;
187397df0d65SSudarsana Reddy Kalluru 		start_addr += size;
187497df0d65SSudarsana Reddy Kalluru 	}
187597df0d65SSudarsana Reddy Kalluru 
187697df0d65SSudarsana Reddy Kalluru 	/* Read A2 section */
187797df0d65SSudarsana Reddy Kalluru 	if (start_addr >= ETH_MODULE_SFF_8079_LEN &&
187897df0d65SSudarsana Reddy Kalluru 	    start_addr < ETH_MODULE_SFF_8472_LEN) {
187997df0d65SSudarsana Reddy Kalluru 		size = ee->len - size;
188097df0d65SSudarsana Reddy Kalluru 		/* Limit transfer size to the A2 section boundary */
188197df0d65SSudarsana Reddy Kalluru 		if (start_addr + size > ETH_MODULE_SFF_8472_LEN)
188297df0d65SSudarsana Reddy Kalluru 			size = ETH_MODULE_SFF_8472_LEN - start_addr;
188397df0d65SSudarsana Reddy Kalluru 		start_addr -= ETH_MODULE_SFF_8079_LEN;
188497df0d65SSudarsana Reddy Kalluru 		rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
188597df0d65SSudarsana Reddy Kalluru 							   QED_I2C_DEV_ADDR_A2,
188697df0d65SSudarsana Reddy Kalluru 							   start_addr, size);
188797df0d65SSudarsana Reddy Kalluru 		if (rc) {
188897df0d65SSudarsana Reddy Kalluru 			DP_VERBOSE(edev, QED_MSG_DEBUG,
188997df0d65SSudarsana Reddy Kalluru 				   "Failed reading A2 section %d\n", rc);
189097df0d65SSudarsana Reddy Kalluru 			return 0;
189197df0d65SSudarsana Reddy Kalluru 		}
189297df0d65SSudarsana Reddy Kalluru 	}
189397df0d65SSudarsana Reddy Kalluru 
189497df0d65SSudarsana Reddy Kalluru 	return rc;
189597df0d65SSudarsana Reddy Kalluru }
189697df0d65SSudarsana Reddy Kalluru 
1897133fac0eSSudarsana Kalluru static const struct ethtool_ops qede_ethtool_ops = {
1898054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1899054c67d1SSudarsana Reddy Kalluru 	.set_link_ksettings = qede_set_link_ksettings,
1900133fac0eSSudarsana Kalluru 	.get_drvinfo = qede_get_drvinfo,
1901e0971c83STomer Tayar 	.get_regs_len = qede_get_regs_len,
1902e0971c83STomer Tayar 	.get_regs = qede_get_regs,
190314d39648SMintz, Yuval 	.get_wol = qede_get_wol,
190414d39648SMintz, Yuval 	.set_wol = qede_set_wol,
1905133fac0eSSudarsana Kalluru 	.get_msglevel = qede_get_msglevel,
1906133fac0eSSudarsana Kalluru 	.set_msglevel = qede_set_msglevel,
190732a7a570SSudarsana Kalluru 	.nway_reset = qede_nway_reset,
1908133fac0eSSudarsana Kalluru 	.get_link = qede_get_link,
1909d552fa84SSudarsana Reddy Kalluru 	.get_coalesce = qede_get_coalesce,
1910d552fa84SSudarsana Reddy Kalluru 	.set_coalesce = qede_set_coalesce,
191101ef7e05SSudarsana Kalluru 	.get_ringparam = qede_get_ringparam,
191201ef7e05SSudarsana Kalluru 	.set_ringparam = qede_set_ringparam,
19130f7db144SSudarsana Kalluru 	.get_pauseparam = qede_get_pauseparam,
19140f7db144SSudarsana Kalluru 	.set_pauseparam = qede_set_pauseparam,
1915133fac0eSSudarsana Kalluru 	.get_strings = qede_get_strings,
19163d971cbdSSudarsana Kalluru 	.set_phys_id = qede_set_phys_id,
1917133fac0eSSudarsana Kalluru 	.get_ethtool_stats = qede_get_ethtool_stats,
1918f3e72109SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1919133fac0eSSudarsana Kalluru 	.get_sset_count = qede_get_sset_count,
1920961acdeaSSudarsana Reddy Kalluru 	.get_rxnfc = qede_get_rxnfc,
1921961acdeaSSudarsana Reddy Kalluru 	.set_rxnfc = qede_set_rxnfc,
1922961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1923961acdeaSSudarsana Reddy Kalluru 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1924961acdeaSSudarsana Reddy Kalluru 	.get_rxfh = qede_get_rxfh,
1925961acdeaSSudarsana Reddy Kalluru 	.set_rxfh = qede_set_rxfh,
19264c55215cSSudarsana Reddy Kalluru 	.get_ts_info = qede_get_ts_info,
19278edf049dSSudarsana Kalluru 	.get_channels = qede_get_channels,
19288edf049dSSudarsana Kalluru 	.set_channels = qede_set_channels,
19293044a02eSSudarsana Reddy Kalluru 	.self_test = qede_self_test,
193097df0d65SSudarsana Reddy Kalluru 	.get_module_info = qede_get_module_info,
193197df0d65SSudarsana Reddy Kalluru 	.get_module_eeprom = qede_get_module_eeprom,
1932c3dc48f7SSudarsana Reddy Kalluru 	.get_eee = qede_get_eee,
1933c3dc48f7SSudarsana Reddy Kalluru 	.set_eee = qede_set_eee,
1934c3dc48f7SSudarsana Reddy Kalluru 
19353d789994SManish Chopra 	.get_tunable = qede_get_tunable,
19363d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1937ccfa110cSSudarsana Reddy Kalluru 	.flash_device = qede_flash_device,
1938133fac0eSSudarsana Kalluru };
1939133fac0eSSudarsana Kalluru 
1940fefb0202SYuval Mintz static const struct ethtool_ops qede_vf_ethtool_ops = {
1941054c67d1SSudarsana Reddy Kalluru 	.get_link_ksettings = qede_get_link_ksettings,
1942fefb0202SYuval Mintz 	.get_drvinfo = qede_get_drvinfo,
1943fefb0202SYuval Mintz 	.get_msglevel = qede_get_msglevel,
1944fefb0202SYuval Mintz 	.set_msglevel = qede_set_msglevel,
1945fefb0202SYuval Mintz 	.get_link = qede_get_link,
1946477f2d14SRahul Verma 	.get_coalesce = qede_get_coalesce,
1947477f2d14SRahul Verma 	.set_coalesce = qede_set_coalesce,
1948fefb0202SYuval Mintz 	.get_ringparam = qede_get_ringparam,
1949fefb0202SYuval Mintz 	.set_ringparam = qede_set_ringparam,
1950fefb0202SYuval Mintz 	.get_strings = qede_get_strings,
1951fefb0202SYuval Mintz 	.get_ethtool_stats = qede_get_ethtool_stats,
1952fefb0202SYuval Mintz 	.get_priv_flags = qede_get_priv_flags,
1953fefb0202SYuval Mintz 	.get_sset_count = qede_get_sset_count,
1954fefb0202SYuval Mintz 	.get_rxnfc = qede_get_rxnfc,
1955fefb0202SYuval Mintz 	.set_rxnfc = qede_set_rxnfc,
1956fefb0202SYuval Mintz 	.get_rxfh_indir_size = qede_get_rxfh_indir_size,
1957fefb0202SYuval Mintz 	.get_rxfh_key_size = qede_get_rxfh_key_size,
1958fefb0202SYuval Mintz 	.get_rxfh = qede_get_rxfh,
1959fefb0202SYuval Mintz 	.set_rxfh = qede_set_rxfh,
1960fefb0202SYuval Mintz 	.get_channels = qede_get_channels,
1961fefb0202SYuval Mintz 	.set_channels = qede_set_channels,
19623d789994SManish Chopra 	.get_tunable = qede_get_tunable,
19633d789994SManish Chopra 	.set_tunable = qede_set_tunable,
1964fefb0202SYuval Mintz };
1965fefb0202SYuval Mintz 
1966133fac0eSSudarsana Kalluru void qede_set_ethtool_ops(struct net_device *dev)
1967133fac0eSSudarsana Kalluru {
1968fefb0202SYuval Mintz 	struct qede_dev *edev = netdev_priv(dev);
1969fefb0202SYuval Mintz 
1970fefb0202SYuval Mintz 	if (IS_VF(edev))
1971fefb0202SYuval Mintz 		dev->ethtool_ops = &qede_vf_ethtool_ops;
1972fefb0202SYuval Mintz 	else
1973133fac0eSSudarsana Kalluru 		dev->ethtool_ops = &qede_ethtool_ops;
1974133fac0eSSudarsana Kalluru }
1975