12246cbc2SShay Agroskin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
21738cd3eSNetanel Belgazal /*
32246cbc2SShay Agroskin  * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
41738cd3eSNetanel Belgazal  */
51738cd3eSNetanel Belgazal 
6cc69837fSJakub Kicinski #include <linux/ethtool.h>
71738cd3eSNetanel Belgazal #include <linux/pci.h>
81738cd3eSNetanel Belgazal 
91738cd3eSNetanel Belgazal #include "ena_netdev.h"
10c891d767SDavid Arinzon #include "ena_xdp.h"
111738cd3eSNetanel Belgazal 
121738cd3eSNetanel Belgazal struct ena_stats {
131738cd3eSNetanel Belgazal 	char name[ETH_GSTRING_LEN];
141738cd3eSNetanel Belgazal 	int stat_offset;
151738cd3eSNetanel Belgazal };
161738cd3eSNetanel Belgazal 
171738cd3eSNetanel Belgazal #define ENA_STAT_ENA_COM_ENTRY(stat) { \
181738cd3eSNetanel Belgazal 	.name = #stat, \
19f1852d64SSameeh Jubran 	.stat_offset = offsetof(struct ena_com_stats_admin, stat) / sizeof(u64) \
201738cd3eSNetanel Belgazal }
211738cd3eSNetanel Belgazal 
221738cd3eSNetanel Belgazal #define ENA_STAT_ENTRY(stat, stat_type) { \
231738cd3eSNetanel Belgazal 	.name = #stat, \
24f1852d64SSameeh Jubran 	.stat_offset = offsetof(struct ena_stats_##stat_type, stat) / sizeof(u64) \
251738cd3eSNetanel Belgazal }
261738cd3eSNetanel Belgazal 
27713865daSSameeh Jubran #define ENA_STAT_HW_ENTRY(stat, stat_type) { \
28713865daSSameeh Jubran 	.name = #stat, \
29713865daSSameeh Jubran 	.stat_offset = offsetof(struct ena_admin_##stat_type, stat) / sizeof(u64) \
30713865daSSameeh Jubran }
31713865daSSameeh Jubran 
321738cd3eSNetanel Belgazal #define ENA_STAT_RX_ENTRY(stat) \
331738cd3eSNetanel Belgazal 	ENA_STAT_ENTRY(stat, rx)
341738cd3eSNetanel Belgazal 
351738cd3eSNetanel Belgazal #define ENA_STAT_TX_ENTRY(stat) \
361738cd3eSNetanel Belgazal 	ENA_STAT_ENTRY(stat, tx)
371738cd3eSNetanel Belgazal 
381738cd3eSNetanel Belgazal #define ENA_STAT_GLOBAL_ENTRY(stat) \
391738cd3eSNetanel Belgazal 	ENA_STAT_ENTRY(stat, dev)
401738cd3eSNetanel Belgazal 
41713865daSSameeh Jubran #define ENA_STAT_ENI_ENTRY(stat) \
42713865daSSameeh Jubran 	ENA_STAT_HW_ENTRY(stat, eni_stats)
43713865daSSameeh Jubran 
441738cd3eSNetanel Belgazal static const struct ena_stats ena_stats_global_strings[] = {
451738cd3eSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(tx_timeout),
468c5c7abdSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(suspend),
478c5c7abdSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(resume),
481738cd3eSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(wd_expired),
491738cd3eSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(interface_up),
501738cd3eSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(interface_down),
511738cd3eSNetanel Belgazal 	ENA_STAT_GLOBAL_ENTRY(admin_q_pause),
521738cd3eSNetanel Belgazal };
531738cd3eSNetanel Belgazal 
54713865daSSameeh Jubran static const struct ena_stats ena_stats_eni_strings[] = {
55713865daSSameeh Jubran 	ENA_STAT_ENI_ENTRY(bw_in_allowance_exceeded),
56713865daSSameeh Jubran 	ENA_STAT_ENI_ENTRY(bw_out_allowance_exceeded),
57713865daSSameeh Jubran 	ENA_STAT_ENI_ENTRY(pps_allowance_exceeded),
58713865daSSameeh Jubran 	ENA_STAT_ENI_ENTRY(conntrack_allowance_exceeded),
59713865daSSameeh Jubran 	ENA_STAT_ENI_ENTRY(linklocal_allowance_exceeded),
60713865daSSameeh Jubran };
61713865daSSameeh Jubran 
621738cd3eSNetanel Belgazal static const struct ena_stats ena_stats_tx_strings[] = {
631738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(cnt),
641738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(bytes),
651738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(queue_stop),
661738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(queue_wakeup),
671738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(dma_mapping_err),
681738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(linearize),
691738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(linearize_failed),
701738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(napi_comp),
711738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(tx_poll),
721738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(doorbells),
731738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(prepare_ctx_err),
741738cd3eSNetanel Belgazal 	ENA_STAT_TX_ENTRY(bad_req_id),
7538005ca8SArthur Kiyanovski 	ENA_STAT_TX_ENTRY(llq_buffer_copy),
7611095fdbSNetanel Belgazal 	ENA_STAT_TX_ENTRY(missed_tx),
77d4a8b3bbSSameeh Jubran 	ENA_STAT_TX_ENTRY(unmask_interrupt),
781738cd3eSNetanel Belgazal };
791738cd3eSNetanel Belgazal 
801738cd3eSNetanel Belgazal static const struct ena_stats ena_stats_rx_strings[] = {
811738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(cnt),
821738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(bytes),
83d2eecc6eSSameeh Jubran 	ENA_STAT_RX_ENTRY(rx_copybreak_pkt),
84d2eecc6eSSameeh Jubran 	ENA_STAT_RX_ENTRY(csum_good),
851738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(refil_partial),
86d0e8831dSArthur Kiyanovski 	ENA_STAT_RX_ENTRY(csum_bad),
871738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(page_alloc_fail),
881738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(skb_alloc_fail),
891738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(dma_mapping_err),
901738cd3eSNetanel Belgazal 	ENA_STAT_RX_ENTRY(bad_desc_num),
91ad974baeSNetanel Belgazal 	ENA_STAT_RX_ENTRY(bad_req_id),
92a3af7c18SNetanel Belgazal 	ENA_STAT_RX_ENTRY(empty_rx_ring),
93cb36bb36SArthur Kiyanovski 	ENA_STAT_RX_ENTRY(csum_unchecked),
944cd28b21SSameeh Jubran 	ENA_STAT_RX_ENTRY(xdp_aborted),
954cd28b21SSameeh Jubran 	ENA_STAT_RX_ENTRY(xdp_drop),
964cd28b21SSameeh Jubran 	ENA_STAT_RX_ENTRY(xdp_pass),
974cd28b21SSameeh Jubran 	ENA_STAT_RX_ENTRY(xdp_tx),
984cd28b21SSameeh Jubran 	ENA_STAT_RX_ENTRY(xdp_invalid),
99a318c70aSShay Agroskin 	ENA_STAT_RX_ENTRY(xdp_redirect),
1001738cd3eSNetanel Belgazal };
1011738cd3eSNetanel Belgazal 
1021738cd3eSNetanel Belgazal static const struct ena_stats ena_stats_ena_com_strings[] = {
1031738cd3eSNetanel Belgazal 	ENA_STAT_ENA_COM_ENTRY(aborted_cmd),
1041738cd3eSNetanel Belgazal 	ENA_STAT_ENA_COM_ENTRY(submitted_cmd),
1051738cd3eSNetanel Belgazal 	ENA_STAT_ENA_COM_ENTRY(completed_cmd),
1061738cd3eSNetanel Belgazal 	ENA_STAT_ENA_COM_ENTRY(out_of_space),
1071738cd3eSNetanel Belgazal 	ENA_STAT_ENA_COM_ENTRY(no_completion),
1081738cd3eSNetanel Belgazal };
1091738cd3eSNetanel Belgazal 
1101738cd3eSNetanel Belgazal #define ENA_STATS_ARRAY_GLOBAL		ARRAY_SIZE(ena_stats_global_strings)
1111738cd3eSNetanel Belgazal #define ENA_STATS_ARRAY_TX		ARRAY_SIZE(ena_stats_tx_strings)
1121738cd3eSNetanel Belgazal #define ENA_STATS_ARRAY_RX		ARRAY_SIZE(ena_stats_rx_strings)
1131738cd3eSNetanel Belgazal #define ENA_STATS_ARRAY_ENA_COM		ARRAY_SIZE(ena_stats_ena_com_strings)
114394c48e0SArthur Kiyanovski #define ENA_STATS_ARRAY_ENI(adapter)	ARRAY_SIZE(ena_stats_eni_strings)
1151738cd3eSNetanel Belgazal 
ena_safe_update_stat(u64 * src,u64 * dst,struct u64_stats_sync * syncp)1161738cd3eSNetanel Belgazal static void ena_safe_update_stat(u64 *src, u64 *dst,
1171738cd3eSNetanel Belgazal 				 struct u64_stats_sync *syncp)
1181738cd3eSNetanel Belgazal {
1191738cd3eSNetanel Belgazal 	unsigned int start;
1201738cd3eSNetanel Belgazal 
1211738cd3eSNetanel Belgazal 	do {
122068c38adSThomas Gleixner 		start = u64_stats_fetch_begin(syncp);
1231738cd3eSNetanel Belgazal 		*(dst) = *src;
124068c38adSThomas Gleixner 	} while (u64_stats_fetch_retry(syncp, start));
1251738cd3eSNetanel Belgazal }
1261738cd3eSNetanel Belgazal 
ena_queue_stats(struct ena_adapter * adapter,u64 ** data)1271738cd3eSNetanel Belgazal static void ena_queue_stats(struct ena_adapter *adapter, u64 **data)
1281738cd3eSNetanel Belgazal {
1291738cd3eSNetanel Belgazal 	const struct ena_stats *ena_stats;
1301738cd3eSNetanel Belgazal 	struct ena_ring *ring;
1311738cd3eSNetanel Belgazal 
1321738cd3eSNetanel Belgazal 	u64 *ptr;
1331738cd3eSNetanel Belgazal 	int i, j;
1341738cd3eSNetanel Belgazal 
1350201bda1SSameeh Jubran 	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
1361738cd3eSNetanel Belgazal 		/* Tx stats */
1371738cd3eSNetanel Belgazal 		ring = &adapter->tx_ring[i];
1381738cd3eSNetanel Belgazal 
1391738cd3eSNetanel Belgazal 		for (j = 0; j < ENA_STATS_ARRAY_TX; j++) {
1401738cd3eSNetanel Belgazal 			ena_stats = &ena_stats_tx_strings[j];
1411738cd3eSNetanel Belgazal 
142f1852d64SSameeh Jubran 			ptr = (u64 *)&ring->tx_stats + ena_stats->stat_offset;
1431738cd3eSNetanel Belgazal 
1441738cd3eSNetanel Belgazal 			ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
1451738cd3eSNetanel Belgazal 		}
1460201bda1SSameeh Jubran 		/* XDP TX queues don't have a RX queue counterpart */
1470201bda1SSameeh Jubran 		if (!ENA_IS_XDP_INDEX(adapter, i)) {
1481738cd3eSNetanel Belgazal 			/* Rx stats */
1491738cd3eSNetanel Belgazal 			ring = &adapter->rx_ring[i];
1501738cd3eSNetanel Belgazal 
1511738cd3eSNetanel Belgazal 			for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
1521738cd3eSNetanel Belgazal 				ena_stats = &ena_stats_rx_strings[j];
1531738cd3eSNetanel Belgazal 
154f1852d64SSameeh Jubran 				ptr = (u64 *)&ring->rx_stats +
155f1852d64SSameeh Jubran 					ena_stats->stat_offset;
1561738cd3eSNetanel Belgazal 
1571738cd3eSNetanel Belgazal 				ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
1581738cd3eSNetanel Belgazal 			}
1591738cd3eSNetanel Belgazal 		}
1601738cd3eSNetanel Belgazal 	}
1610201bda1SSameeh Jubran }
1621738cd3eSNetanel Belgazal 
ena_dev_admin_queue_stats(struct ena_adapter * adapter,u64 ** data)1631738cd3eSNetanel Belgazal static void ena_dev_admin_queue_stats(struct ena_adapter *adapter, u64 **data)
1641738cd3eSNetanel Belgazal {
1651738cd3eSNetanel Belgazal 	const struct ena_stats *ena_stats;
1660dcec686SArthur Kiyanovski 	u64 *ptr;
1671738cd3eSNetanel Belgazal 	int i;
1681738cd3eSNetanel Belgazal 
1691738cd3eSNetanel Belgazal 	for (i = 0; i < ENA_STATS_ARRAY_ENA_COM; i++) {
1701738cd3eSNetanel Belgazal 		ena_stats = &ena_stats_ena_com_strings[i];
1711738cd3eSNetanel Belgazal 
172f1852d64SSameeh Jubran 		ptr = (u64 *)&adapter->ena_dev->admin_queue.stats +
173f1852d64SSameeh Jubran 			ena_stats->stat_offset;
1741738cd3eSNetanel Belgazal 
1751738cd3eSNetanel Belgazal 		*(*data)++ = *ptr;
1761738cd3eSNetanel Belgazal 	}
1771738cd3eSNetanel Belgazal }
1781738cd3eSNetanel Belgazal 
ena_get_stats(struct ena_adapter * adapter,u64 * data,bool eni_stats_needed)179713865daSSameeh Jubran static void ena_get_stats(struct ena_adapter *adapter,
180713865daSSameeh Jubran 			  u64 *data,
181713865daSSameeh Jubran 			  bool eni_stats_needed)
1821738cd3eSNetanel Belgazal {
1831738cd3eSNetanel Belgazal 	const struct ena_stats *ena_stats;
1841738cd3eSNetanel Belgazal 	u64 *ptr;
1851738cd3eSNetanel Belgazal 	int i;
1861738cd3eSNetanel Belgazal 
1871738cd3eSNetanel Belgazal 	for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
1881738cd3eSNetanel Belgazal 		ena_stats = &ena_stats_global_strings[i];
1891738cd3eSNetanel Belgazal 
190f1852d64SSameeh Jubran 		ptr = (u64 *)&adapter->dev_stats + ena_stats->stat_offset;
1911738cd3eSNetanel Belgazal 
1921738cd3eSNetanel Belgazal 		ena_safe_update_stat(ptr, data++, &adapter->syncp);
1931738cd3eSNetanel Belgazal 	}
1941738cd3eSNetanel Belgazal 
195713865daSSameeh Jubran 	if (eni_stats_needed) {
196713865daSSameeh Jubran 		ena_update_hw_stats(adapter);
197713865daSSameeh Jubran 		for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
198713865daSSameeh Jubran 			ena_stats = &ena_stats_eni_strings[i];
199713865daSSameeh Jubran 
200713865daSSameeh Jubran 			ptr = (u64 *)&adapter->eni_stats +
201713865daSSameeh Jubran 				ena_stats->stat_offset;
202713865daSSameeh Jubran 
203713865daSSameeh Jubran 			ena_safe_update_stat(ptr, data++, &adapter->syncp);
204713865daSSameeh Jubran 		}
205713865daSSameeh Jubran 	}
206713865daSSameeh Jubran 
2071738cd3eSNetanel Belgazal 	ena_queue_stats(adapter, &data);
2081738cd3eSNetanel Belgazal 	ena_dev_admin_queue_stats(adapter, &data);
2091738cd3eSNetanel Belgazal }
2101738cd3eSNetanel Belgazal 
ena_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)211713865daSSameeh Jubran static void ena_get_ethtool_stats(struct net_device *netdev,
212713865daSSameeh Jubran 				  struct ethtool_stats *stats,
213713865daSSameeh Jubran 				  u64 *data)
214713865daSSameeh Jubran {
215713865daSSameeh Jubran 	struct ena_adapter *adapter = netdev_priv(netdev);
216394c48e0SArthur Kiyanovski 	struct ena_com_dev *dev = adapter->ena_dev;
217713865daSSameeh Jubran 
218394c48e0SArthur Kiyanovski 	ena_get_stats(adapter, data, ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS));
219713865daSSameeh Jubran }
220713865daSSameeh Jubran 
ena_get_sw_stats_count(struct ena_adapter * adapter)221713865daSSameeh Jubran static int ena_get_sw_stats_count(struct ena_adapter *adapter)
222713865daSSameeh Jubran {
223713865daSSameeh Jubran 	return adapter->num_io_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
2240201bda1SSameeh Jubran 		+ adapter->xdp_num_queues * ENA_STATS_ARRAY_TX
225713865daSSameeh Jubran 		+ ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
226713865daSSameeh Jubran }
227713865daSSameeh Jubran 
ena_get_hw_stats_count(struct ena_adapter * adapter)228713865daSSameeh Jubran static int ena_get_hw_stats_count(struct ena_adapter *adapter)
229713865daSSameeh Jubran {
230394c48e0SArthur Kiyanovski 	bool supported = ena_com_get_cap(adapter->ena_dev, ENA_ADMIN_ENI_STATS);
231394c48e0SArthur Kiyanovski 
232394c48e0SArthur Kiyanovski 	return ENA_STATS_ARRAY_ENI(adapter) * supported;
233713865daSSameeh Jubran }
234713865daSSameeh Jubran 
ena_get_sset_count(struct net_device * netdev,int sset)2351738cd3eSNetanel Belgazal int ena_get_sset_count(struct net_device *netdev, int sset)
2361738cd3eSNetanel Belgazal {
2371738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
2381738cd3eSNetanel Belgazal 
239a01f2cd0SShay Agroskin 	switch (sset) {
240a01f2cd0SShay Agroskin 	case ETH_SS_STATS:
241a01f2cd0SShay Agroskin 		return ena_get_sw_stats_count(adapter) +
242a01f2cd0SShay Agroskin 		       ena_get_hw_stats_count(adapter);
243a01f2cd0SShay Agroskin 	}
244eb203baeSJakub Kicinski 
245a01f2cd0SShay Agroskin 	return -EOPNOTSUPP;
2461738cd3eSNetanel Belgazal }
2471738cd3eSNetanel Belgazal 
ena_queue_strings(struct ena_adapter * adapter,u8 ** data)2481738cd3eSNetanel Belgazal static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
2491738cd3eSNetanel Belgazal {
2501738cd3eSNetanel Belgazal 	const struct ena_stats *ena_stats;
2510201bda1SSameeh Jubran 	bool is_xdp;
2521738cd3eSNetanel Belgazal 	int i, j;
2531738cd3eSNetanel Belgazal 
2540201bda1SSameeh Jubran 	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
2550201bda1SSameeh Jubran 		is_xdp = ENA_IS_XDP_INDEX(adapter, i);
2561738cd3eSNetanel Belgazal 		/* Tx stats */
2571738cd3eSNetanel Belgazal 		for (j = 0; j < ENA_STATS_ARRAY_TX; j++) {
2581738cd3eSNetanel Belgazal 			ena_stats = &ena_stats_tx_strings[j];
2591738cd3eSNetanel Belgazal 
260efbbe4fbSAlexander Duyck 			ethtool_sprintf(data,
2610201bda1SSameeh Jubran 					"queue_%u_%s_%s", i,
262efbbe4fbSAlexander Duyck 					is_xdp ? "xdp_tx" : "tx",
263efbbe4fbSAlexander Duyck 					ena_stats->name);
2641738cd3eSNetanel Belgazal 		}
2650201bda1SSameeh Jubran 
2660201bda1SSameeh Jubran 		if (!is_xdp) {
2670201bda1SSameeh Jubran 			/* RX stats, in XDP there isn't a RX queue
2680201bda1SSameeh Jubran 			 * counterpart
2690201bda1SSameeh Jubran 			 */
2701738cd3eSNetanel Belgazal 			for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
2711738cd3eSNetanel Belgazal 				ena_stats = &ena_stats_rx_strings[j];
2721738cd3eSNetanel Belgazal 
273efbbe4fbSAlexander Duyck 				ethtool_sprintf(data,
274efbbe4fbSAlexander Duyck 						"queue_%u_rx_%s", i,
275efbbe4fbSAlexander Duyck 						ena_stats->name);
2761738cd3eSNetanel Belgazal 			}
2771738cd3eSNetanel Belgazal 		}
2781738cd3eSNetanel Belgazal 	}
2790201bda1SSameeh Jubran }
2801738cd3eSNetanel Belgazal 
ena_com_dev_strings(u8 ** data)2811738cd3eSNetanel Belgazal static void ena_com_dev_strings(u8 **data)
2821738cd3eSNetanel Belgazal {
2831738cd3eSNetanel Belgazal 	const struct ena_stats *ena_stats;
2841738cd3eSNetanel Belgazal 	int i;
2851738cd3eSNetanel Belgazal 
2861738cd3eSNetanel Belgazal 	for (i = 0; i < ENA_STATS_ARRAY_ENA_COM; i++) {
2871738cd3eSNetanel Belgazal 		ena_stats = &ena_stats_ena_com_strings[i];
2881738cd3eSNetanel Belgazal 
289efbbe4fbSAlexander Duyck 		ethtool_sprintf(data,
2901738cd3eSNetanel Belgazal 				"ena_admin_q_%s", ena_stats->name);
2911738cd3eSNetanel Belgazal 	}
2921738cd3eSNetanel Belgazal }
2931738cd3eSNetanel Belgazal 
ena_get_strings(struct ena_adapter * adapter,u8 * data,bool eni_stats_needed)294713865daSSameeh Jubran static void ena_get_strings(struct ena_adapter *adapter,
295713865daSSameeh Jubran 			    u8 *data,
296713865daSSameeh Jubran 			    bool eni_stats_needed)
297315c28d2SArthur Kiyanovski {
298eb203baeSJakub Kicinski 	const struct ena_stats *ena_stats;
299eb203baeSJakub Kicinski 	int i;
300315c28d2SArthur Kiyanovski 
301eb203baeSJakub Kicinski 	for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
302eb203baeSJakub Kicinski 		ena_stats = &ena_stats_global_strings[i];
303efbbe4fbSAlexander Duyck 		ethtool_sprintf(&data, ena_stats->name);
304315c28d2SArthur Kiyanovski 	}
305eb203baeSJakub Kicinski 
306713865daSSameeh Jubran 	if (eni_stats_needed) {
307713865daSSameeh Jubran 		for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
308713865daSSameeh Jubran 			ena_stats = &ena_stats_eni_strings[i];
309efbbe4fbSAlexander Duyck 			ethtool_sprintf(&data, ena_stats->name);
310713865daSSameeh Jubran 		}
311713865daSSameeh Jubran 	}
312713865daSSameeh Jubran 
313eb203baeSJakub Kicinski 	ena_queue_strings(adapter, &data);
314eb203baeSJakub Kicinski 	ena_com_dev_strings(&data);
315315c28d2SArthur Kiyanovski }
316315c28d2SArthur Kiyanovski 
ena_get_ethtool_strings(struct net_device * netdev,u32 sset,u8 * data)317713865daSSameeh Jubran static void ena_get_ethtool_strings(struct net_device *netdev,
318713865daSSameeh Jubran 				    u32 sset,
319713865daSSameeh Jubran 				    u8 *data)
320713865daSSameeh Jubran {
321713865daSSameeh Jubran 	struct ena_adapter *adapter = netdev_priv(netdev);
322394c48e0SArthur Kiyanovski 	struct ena_com_dev *dev = adapter->ena_dev;
323713865daSSameeh Jubran 
324a01f2cd0SShay Agroskin 	switch (sset) {
325a01f2cd0SShay Agroskin 	case ETH_SS_STATS:
326394c48e0SArthur Kiyanovski 		ena_get_strings(adapter, data, ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS));
327a01f2cd0SShay Agroskin 		break;
328a01f2cd0SShay Agroskin 	}
329713865daSSameeh Jubran }
330713865daSSameeh Jubran 
ena_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * link_ksettings)3311738cd3eSNetanel Belgazal static int ena_get_link_ksettings(struct net_device *netdev,
3321738cd3eSNetanel Belgazal 				  struct ethtool_link_ksettings *link_ksettings)
3331738cd3eSNetanel Belgazal {
3341738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
3351738cd3eSNetanel Belgazal 	struct ena_com_dev *ena_dev = adapter->ena_dev;
3361738cd3eSNetanel Belgazal 	struct ena_admin_get_feature_link_desc *link;
3371738cd3eSNetanel Belgazal 	struct ena_admin_get_feat_resp feat_resp;
3381738cd3eSNetanel Belgazal 	int rc;
3391738cd3eSNetanel Belgazal 
3401738cd3eSNetanel Belgazal 	rc = ena_com_get_link_params(ena_dev, &feat_resp);
3411738cd3eSNetanel Belgazal 	if (rc)
3421738cd3eSNetanel Belgazal 		return rc;
3431738cd3eSNetanel Belgazal 
3441738cd3eSNetanel Belgazal 	link = &feat_resp.u.link;
3451738cd3eSNetanel Belgazal 	link_ksettings->base.speed = link->speed;
3461738cd3eSNetanel Belgazal 
3471738cd3eSNetanel Belgazal 	if (link->flags & ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK) {
3481738cd3eSNetanel Belgazal 		ethtool_link_ksettings_add_link_mode(link_ksettings,
3491738cd3eSNetanel Belgazal 						     supported, Autoneg);
3501738cd3eSNetanel Belgazal 		ethtool_link_ksettings_add_link_mode(link_ksettings,
3511738cd3eSNetanel Belgazal 						     supported, Autoneg);
3521738cd3eSNetanel Belgazal 	}
3531738cd3eSNetanel Belgazal 
3541738cd3eSNetanel Belgazal 	link_ksettings->base.autoneg =
3551738cd3eSNetanel Belgazal 		(link->flags & ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK) ?
3561738cd3eSNetanel Belgazal 		AUTONEG_ENABLE : AUTONEG_DISABLE;
3571738cd3eSNetanel Belgazal 
3581738cd3eSNetanel Belgazal 	link_ksettings->base.duplex = DUPLEX_FULL;
3591738cd3eSNetanel Belgazal 
3601738cd3eSNetanel Belgazal 	return 0;
3611738cd3eSNetanel Belgazal }
3621738cd3eSNetanel Belgazal 
ena_get_coalesce(struct net_device * net_dev,struct ethtool_coalesce * coalesce,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)3631738cd3eSNetanel Belgazal static int ena_get_coalesce(struct net_device *net_dev,
364f3ccfda1SYufeng Mo 			    struct ethtool_coalesce *coalesce,
365f3ccfda1SYufeng Mo 			    struct kernel_ethtool_coalesce *kernel_coal,
366f3ccfda1SYufeng Mo 			    struct netlink_ext_ack *extack)
3671738cd3eSNetanel Belgazal {
3681738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(net_dev);
3691738cd3eSNetanel Belgazal 	struct ena_com_dev *ena_dev = adapter->ena_dev;
3701738cd3eSNetanel Belgazal 
371f3020447SArthur Kiyanovski 	if (!ena_com_interrupt_moderation_supported(ena_dev))
3721738cd3eSNetanel Belgazal 		return -EOPNOTSUPP;
3730eda8479SArthur Kiyanovski 
3741738cd3eSNetanel Belgazal 	coalesce->tx_coalesce_usecs =
3750eda8479SArthur Kiyanovski 		ena_com_get_nonadaptive_moderation_interval_tx(ena_dev) *
3761738cd3eSNetanel Belgazal 			ena_dev->intr_delay_resolution;
377b3db86dcSArthur Kiyanovski 
3781738cd3eSNetanel Belgazal 	coalesce->rx_coalesce_usecs =
3791738cd3eSNetanel Belgazal 		ena_com_get_nonadaptive_moderation_interval_rx(ena_dev)
3800eda8479SArthur Kiyanovski 		* ena_dev->intr_delay_resolution;
3811738cd3eSNetanel Belgazal 
3821738cd3eSNetanel Belgazal 	coalesce->use_adaptive_rx_coalesce =
3831738cd3eSNetanel Belgazal 		ena_com_get_adaptive_moderation_enabled(ena_dev);
3841738cd3eSNetanel Belgazal 
3851738cd3eSNetanel Belgazal 	return 0;
3861738cd3eSNetanel Belgazal }
3871738cd3eSNetanel Belgazal 
ena_update_tx_rings_nonadaptive_intr_moderation(struct ena_adapter * adapter)38895d0fcb5SArthur Kiyanovski static void ena_update_tx_rings_nonadaptive_intr_moderation(struct ena_adapter *adapter)
3891738cd3eSNetanel Belgazal {
3901738cd3eSNetanel Belgazal 	unsigned int val;
3911738cd3eSNetanel Belgazal 	int i;
3921738cd3eSNetanel Belgazal 
3931738cd3eSNetanel Belgazal 	val = ena_com_get_nonadaptive_moderation_interval_tx(adapter->ena_dev);
3941738cd3eSNetanel Belgazal 
395faa615f9SSameeh Jubran 	for (i = 0; i < adapter->num_io_queues; i++)
3961738cd3eSNetanel Belgazal 		adapter->tx_ring[i].smoothed_interval = val;
3971738cd3eSNetanel Belgazal }
3981738cd3eSNetanel Belgazal 
ena_update_rx_rings_nonadaptive_intr_moderation(struct ena_adapter * adapter)39995d0fcb5SArthur Kiyanovski static void ena_update_rx_rings_nonadaptive_intr_moderation(struct ena_adapter *adapter)
400b3db86dcSArthur Kiyanovski {
401b3db86dcSArthur Kiyanovski 	unsigned int val;
402b3db86dcSArthur Kiyanovski 	int i;
403b3db86dcSArthur Kiyanovski 
404b3db86dcSArthur Kiyanovski 	val = ena_com_get_nonadaptive_moderation_interval_rx(adapter->ena_dev);
405b3db86dcSArthur Kiyanovski 
406faa615f9SSameeh Jubran 	for (i = 0; i < adapter->num_io_queues; i++)
407b3db86dcSArthur Kiyanovski 		adapter->rx_ring[i].smoothed_interval = val;
408b3db86dcSArthur Kiyanovski }
409b3db86dcSArthur Kiyanovski 
ena_set_coalesce(struct net_device * net_dev,struct ethtool_coalesce * coalesce,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)4101738cd3eSNetanel Belgazal static int ena_set_coalesce(struct net_device *net_dev,
411f3ccfda1SYufeng Mo 			    struct ethtool_coalesce *coalesce,
412f3ccfda1SYufeng Mo 			    struct kernel_ethtool_coalesce *kernel_coal,
413f3ccfda1SYufeng Mo 			    struct netlink_ext_ack *extack)
4141738cd3eSNetanel Belgazal {
4151738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(net_dev);
4161738cd3eSNetanel Belgazal 	struct ena_com_dev *ena_dev = adapter->ena_dev;
4171738cd3eSNetanel Belgazal 	int rc;
4181738cd3eSNetanel Belgazal 
419f3020447SArthur Kiyanovski 	if (!ena_com_interrupt_moderation_supported(ena_dev))
4201738cd3eSNetanel Belgazal 		return -EOPNOTSUPP;
4211738cd3eSNetanel Belgazal 
4221738cd3eSNetanel Belgazal 	rc = ena_com_update_nonadaptive_moderation_interval_tx(ena_dev,
4231738cd3eSNetanel Belgazal 							       coalesce->tx_coalesce_usecs);
4241738cd3eSNetanel Belgazal 	if (rc)
4251738cd3eSNetanel Belgazal 		return rc;
4261738cd3eSNetanel Belgazal 
42795d0fcb5SArthur Kiyanovski 	ena_update_tx_rings_nonadaptive_intr_moderation(adapter);
4281738cd3eSNetanel Belgazal 
4291738cd3eSNetanel Belgazal 	rc = ena_com_update_nonadaptive_moderation_interval_rx(ena_dev,
4301738cd3eSNetanel Belgazal 							       coalesce->rx_coalesce_usecs);
431b3db86dcSArthur Kiyanovski 	if (rc)
4321738cd3eSNetanel Belgazal 		return rc;
433b3db86dcSArthur Kiyanovski 
43495d0fcb5SArthur Kiyanovski 	ena_update_rx_rings_nonadaptive_intr_moderation(adapter);
435b3db86dcSArthur Kiyanovski 
43641c53caaSArthur Kiyanovski 	if (coalesce->use_adaptive_rx_coalesce &&
43741c53caaSArthur Kiyanovski 	    !ena_com_get_adaptive_moderation_enabled(ena_dev))
43841c53caaSArthur Kiyanovski 		ena_com_enable_adaptive_moderation(ena_dev);
43941c53caaSArthur Kiyanovski 
44041c53caaSArthur Kiyanovski 	if (!coalesce->use_adaptive_rx_coalesce &&
44141c53caaSArthur Kiyanovski 	    ena_com_get_adaptive_moderation_enabled(ena_dev))
442b3db86dcSArthur Kiyanovski 		ena_com_disable_adaptive_moderation(ena_dev);
4431738cd3eSNetanel Belgazal 
4441738cd3eSNetanel Belgazal 	return 0;
4451738cd3eSNetanel Belgazal }
4461738cd3eSNetanel Belgazal 
ena_get_msglevel(struct net_device * netdev)4471738cd3eSNetanel Belgazal static u32 ena_get_msglevel(struct net_device *netdev)
4481738cd3eSNetanel Belgazal {
4491738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
4501738cd3eSNetanel Belgazal 
4511738cd3eSNetanel Belgazal 	return adapter->msg_enable;
4521738cd3eSNetanel Belgazal }
4531738cd3eSNetanel Belgazal 
ena_set_msglevel(struct net_device * netdev,u32 value)4541738cd3eSNetanel Belgazal static void ena_set_msglevel(struct net_device *netdev, u32 value)
4551738cd3eSNetanel Belgazal {
4561738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
4571738cd3eSNetanel Belgazal 
4581738cd3eSNetanel Belgazal 	adapter->msg_enable = value;
4591738cd3eSNetanel Belgazal }
4601738cd3eSNetanel Belgazal 
ena_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)4611738cd3eSNetanel Belgazal static void ena_get_drvinfo(struct net_device *dev,
4621738cd3eSNetanel Belgazal 			    struct ethtool_drvinfo *info)
4631738cd3eSNetanel Belgazal {
4641738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(dev);
4651738cd3eSNetanel Belgazal 
466f029c781SWolfram Sang 	strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
467f029c781SWolfram Sang 	strscpy(info->bus_info, pci_name(adapter->pdev),
4681738cd3eSNetanel Belgazal 		sizeof(info->bus_info));
4691738cd3eSNetanel Belgazal }
4701738cd3eSNetanel Belgazal 
ena_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)4711738cd3eSNetanel Belgazal static void ena_get_ringparam(struct net_device *netdev,
47274624944SHao Chen 			      struct ethtool_ringparam *ring,
47374624944SHao Chen 			      struct kernel_ethtool_ringparam *kernel_ring,
47474624944SHao Chen 			      struct netlink_ext_ack *extack)
4751738cd3eSNetanel Belgazal {
4761738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
4771738cd3eSNetanel Belgazal 
4789f9ae3f9SSameeh Jubran 	ring->tx_max_pending = adapter->max_tx_ring_size;
4799f9ae3f9SSameeh Jubran 	ring->rx_max_pending = adapter->max_rx_ring_size;
480b0c59e53SShay Agroskin 	if (adapter->ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
481b0c59e53SShay Agroskin 		bool large_llq_supported = adapter->large_llq_header_supported;
482b0c59e53SShay Agroskin 
483060cdac2SShay Agroskin 		kernel_ring->tx_push = true;
484b0c59e53SShay Agroskin 		kernel_ring->tx_push_buf_len = adapter->ena_dev->tx_max_header_size;
485b0c59e53SShay Agroskin 		if (large_llq_supported)
486b0c59e53SShay Agroskin 			kernel_ring->tx_push_buf_max_len = ENA_LLQ_LARGE_HEADER;
487b0c59e53SShay Agroskin 		else
488b0c59e53SShay Agroskin 			kernel_ring->tx_push_buf_max_len = ENA_LLQ_HEADER;
489b0c59e53SShay Agroskin 	} else {
490060cdac2SShay Agroskin 		kernel_ring->tx_push = false;
491b0c59e53SShay Agroskin 		kernel_ring->tx_push_buf_max_len = 0;
492b0c59e53SShay Agroskin 		kernel_ring->tx_push_buf_len = 0;
493b0c59e53SShay Agroskin 	}
494b0c59e53SShay Agroskin 
49513ca32a6SSameeh Jubran 	ring->tx_pending = adapter->tx_ring[0].ring_size;
49613ca32a6SSameeh Jubran 	ring->rx_pending = adapter->rx_ring[0].ring_size;
4971738cd3eSNetanel Belgazal }
4981738cd3eSNetanel Belgazal 
ena_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)499eece4d2aSSameeh Jubran static int ena_set_ringparam(struct net_device *netdev,
50074624944SHao Chen 			     struct ethtool_ringparam *ring,
50174624944SHao Chen 			     struct kernel_ethtool_ringparam *kernel_ring,
50274624944SHao Chen 			     struct netlink_ext_ack *extack)
503eece4d2aSSameeh Jubran {
504eece4d2aSSameeh Jubran 	struct ena_adapter *adapter = netdev_priv(netdev);
505b0c59e53SShay Agroskin 	u32 new_tx_size, new_rx_size, new_tx_push_buf_len;
506b0c59e53SShay Agroskin 	bool changed = false;
507eece4d2aSSameeh Jubran 
508eece4d2aSSameeh Jubran 	new_tx_size = ring->tx_pending < ENA_MIN_RING_SIZE ?
509eece4d2aSSameeh Jubran 			ENA_MIN_RING_SIZE : ring->tx_pending;
510eece4d2aSSameeh Jubran 	new_tx_size = rounddown_pow_of_two(new_tx_size);
511eece4d2aSSameeh Jubran 
512eece4d2aSSameeh Jubran 	new_rx_size = ring->rx_pending < ENA_MIN_RING_SIZE ?
513eece4d2aSSameeh Jubran 			ENA_MIN_RING_SIZE : ring->rx_pending;
514eece4d2aSSameeh Jubran 	new_rx_size = rounddown_pow_of_two(new_rx_size);
515eece4d2aSSameeh Jubran 
516b0c59e53SShay Agroskin 	changed |= new_tx_size != adapter->requested_tx_ring_size ||
517b0c59e53SShay Agroskin 		   new_rx_size != adapter->requested_rx_ring_size;
518b0c59e53SShay Agroskin 
519b0c59e53SShay Agroskin 	/* This value is ignored if LLQ is not supported */
520b0c59e53SShay Agroskin 	new_tx_push_buf_len = adapter->ena_dev->tx_max_header_size;
521b0c59e53SShay Agroskin 
522060cdac2SShay Agroskin 	if ((adapter->ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) !=
523060cdac2SShay Agroskin 	    kernel_ring->tx_push) {
524060cdac2SShay Agroskin 		NL_SET_ERR_MSG_MOD(extack, "Push mode state cannot be modified");
525060cdac2SShay Agroskin 		return -EINVAL;
526060cdac2SShay Agroskin 	}
527060cdac2SShay Agroskin 
528b0c59e53SShay Agroskin 	/* Validate that the push buffer is supported on the underlying device */
529b0c59e53SShay Agroskin 	if (kernel_ring->tx_push_buf_len) {
530b0c59e53SShay Agroskin 		enum ena_admin_placement_policy_type placement;
531b0c59e53SShay Agroskin 
532b0c59e53SShay Agroskin 		new_tx_push_buf_len = kernel_ring->tx_push_buf_len;
533b0c59e53SShay Agroskin 
534b0c59e53SShay Agroskin 		placement = adapter->ena_dev->tx_mem_queue_type;
535b0c59e53SShay Agroskin 		if (placement == ENA_ADMIN_PLACEMENT_POLICY_HOST)
536b0c59e53SShay Agroskin 			return -EOPNOTSUPP;
537b0c59e53SShay Agroskin 
538b0c59e53SShay Agroskin 		if (new_tx_push_buf_len != ENA_LLQ_HEADER &&
539b0c59e53SShay Agroskin 		    new_tx_push_buf_len != ENA_LLQ_LARGE_HEADER) {
540b0c59e53SShay Agroskin 			bool large_llq_sup = adapter->large_llq_header_supported;
541b0c59e53SShay Agroskin 			char large_llq_size_str[40];
542b0c59e53SShay Agroskin 
543b0c59e53SShay Agroskin 			snprintf(large_llq_size_str, 40, ", %lu", ENA_LLQ_LARGE_HEADER);
544b0c59e53SShay Agroskin 
545b0c59e53SShay Agroskin 			NL_SET_ERR_MSG_FMT_MOD(extack,
546b0c59e53SShay Agroskin 					       "Supported tx push buff values: [%lu%s]",
547b0c59e53SShay Agroskin 					       ENA_LLQ_HEADER,
548b0c59e53SShay Agroskin 					       large_llq_sup ? large_llq_size_str : "");
549b0c59e53SShay Agroskin 
550b0c59e53SShay Agroskin 			return -EINVAL;
551b0c59e53SShay Agroskin 		}
552b0c59e53SShay Agroskin 
553b0c59e53SShay Agroskin 		changed |= new_tx_push_buf_len != adapter->ena_dev->tx_max_header_size;
554b0c59e53SShay Agroskin 	}
555b0c59e53SShay Agroskin 
556b0c59e53SShay Agroskin 	if (!changed)
557eece4d2aSSameeh Jubran 		return 0;
558eece4d2aSSameeh Jubran 
559b0c59e53SShay Agroskin 	return ena_update_queue_params(adapter, new_tx_size, new_rx_size,
560b0c59e53SShay Agroskin 				       new_tx_push_buf_len);
561eece4d2aSSameeh Jubran }
562eece4d2aSSameeh Jubran 
ena_flow_hash_to_flow_type(u16 hash_fields)5631738cd3eSNetanel Belgazal static u32 ena_flow_hash_to_flow_type(u16 hash_fields)
5641738cd3eSNetanel Belgazal {
5651738cd3eSNetanel Belgazal 	u32 data = 0;
5661738cd3eSNetanel Belgazal 
5671738cd3eSNetanel Belgazal 	if (hash_fields & ENA_ADMIN_RSS_L2_DA)
5681738cd3eSNetanel Belgazal 		data |= RXH_L2DA;
5691738cd3eSNetanel Belgazal 
5701738cd3eSNetanel Belgazal 	if (hash_fields & ENA_ADMIN_RSS_L3_DA)
5711738cd3eSNetanel Belgazal 		data |= RXH_IP_DST;
5721738cd3eSNetanel Belgazal 
5731738cd3eSNetanel Belgazal 	if (hash_fields & ENA_ADMIN_RSS_L3_SA)
5741738cd3eSNetanel Belgazal 		data |= RXH_IP_SRC;
5751738cd3eSNetanel Belgazal 
5761738cd3eSNetanel Belgazal 	if (hash_fields & ENA_ADMIN_RSS_L4_DP)
5771738cd3eSNetanel Belgazal 		data |= RXH_L4_B_2_3;
5781738cd3eSNetanel Belgazal 
5791738cd3eSNetanel Belgazal 	if (hash_fields & ENA_ADMIN_RSS_L4_SP)
5801738cd3eSNetanel Belgazal 		data |= RXH_L4_B_0_1;
5811738cd3eSNetanel Belgazal 
5821738cd3eSNetanel Belgazal 	return data;
5831738cd3eSNetanel Belgazal }
5841738cd3eSNetanel Belgazal 
ena_flow_data_to_flow_hash(u32 hash_fields)5851738cd3eSNetanel Belgazal static u16 ena_flow_data_to_flow_hash(u32 hash_fields)
5861738cd3eSNetanel Belgazal {
5871738cd3eSNetanel Belgazal 	u16 data = 0;
5881738cd3eSNetanel Belgazal 
5891738cd3eSNetanel Belgazal 	if (hash_fields & RXH_L2DA)
5901738cd3eSNetanel Belgazal 		data |= ENA_ADMIN_RSS_L2_DA;
5911738cd3eSNetanel Belgazal 
5921738cd3eSNetanel Belgazal 	if (hash_fields & RXH_IP_DST)
5931738cd3eSNetanel Belgazal 		data |= ENA_ADMIN_RSS_L3_DA;
5941738cd3eSNetanel Belgazal 
5951738cd3eSNetanel Belgazal 	if (hash_fields & RXH_IP_SRC)
5961738cd3eSNetanel Belgazal 		data |= ENA_ADMIN_RSS_L3_SA;
5971738cd3eSNetanel Belgazal 
5981738cd3eSNetanel Belgazal 	if (hash_fields & RXH_L4_B_2_3)
5991738cd3eSNetanel Belgazal 		data |= ENA_ADMIN_RSS_L4_DP;
6001738cd3eSNetanel Belgazal 
6011738cd3eSNetanel Belgazal 	if (hash_fields & RXH_L4_B_0_1)
6021738cd3eSNetanel Belgazal 		data |= ENA_ADMIN_RSS_L4_SP;
6031738cd3eSNetanel Belgazal 
6041738cd3eSNetanel Belgazal 	return data;
6051738cd3eSNetanel Belgazal }
6061738cd3eSNetanel Belgazal 
ena_get_rss_hash(struct ena_com_dev * ena_dev,struct ethtool_rxnfc * cmd)6071738cd3eSNetanel Belgazal static int ena_get_rss_hash(struct ena_com_dev *ena_dev,
6081738cd3eSNetanel Belgazal 			    struct ethtool_rxnfc *cmd)
6091738cd3eSNetanel Belgazal {
6101738cd3eSNetanel Belgazal 	enum ena_admin_flow_hash_proto proto;
6111738cd3eSNetanel Belgazal 	u16 hash_fields;
6121738cd3eSNetanel Belgazal 	int rc;
6131738cd3eSNetanel Belgazal 
6141738cd3eSNetanel Belgazal 	cmd->data = 0;
6151738cd3eSNetanel Belgazal 
6161738cd3eSNetanel Belgazal 	switch (cmd->flow_type) {
6171738cd3eSNetanel Belgazal 	case TCP_V4_FLOW:
6181738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_TCP4;
6191738cd3eSNetanel Belgazal 		break;
6201738cd3eSNetanel Belgazal 	case UDP_V4_FLOW:
6211738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_UDP4;
6221738cd3eSNetanel Belgazal 		break;
6231738cd3eSNetanel Belgazal 	case TCP_V6_FLOW:
6241738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_TCP6;
6251738cd3eSNetanel Belgazal 		break;
6261738cd3eSNetanel Belgazal 	case UDP_V6_FLOW:
6271738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_UDP6;
6281738cd3eSNetanel Belgazal 		break;
6291738cd3eSNetanel Belgazal 	case IPV4_FLOW:
6301738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_IP4;
6311738cd3eSNetanel Belgazal 		break;
6321738cd3eSNetanel Belgazal 	case IPV6_FLOW:
6331738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_IP6;
6341738cd3eSNetanel Belgazal 		break;
6351738cd3eSNetanel Belgazal 	case ETHER_FLOW:
6361738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_NOT_IP;
6371738cd3eSNetanel Belgazal 		break;
6381738cd3eSNetanel Belgazal 	case AH_V4_FLOW:
6391738cd3eSNetanel Belgazal 	case ESP_V4_FLOW:
6401738cd3eSNetanel Belgazal 	case AH_V6_FLOW:
6411738cd3eSNetanel Belgazal 	case ESP_V6_FLOW:
6421738cd3eSNetanel Belgazal 	case SCTP_V4_FLOW:
6431738cd3eSNetanel Belgazal 	case AH_ESP_V4_FLOW:
6441738cd3eSNetanel Belgazal 		return -EOPNOTSUPP;
6451738cd3eSNetanel Belgazal 	default:
6461738cd3eSNetanel Belgazal 		return -EINVAL;
6471738cd3eSNetanel Belgazal 	}
6481738cd3eSNetanel Belgazal 
6491738cd3eSNetanel Belgazal 	rc = ena_com_get_hash_ctrl(ena_dev, proto, &hash_fields);
650d1497638SNetanel Belgazal 	if (rc)
6511738cd3eSNetanel Belgazal 		return rc;
6521738cd3eSNetanel Belgazal 
6531738cd3eSNetanel Belgazal 	cmd->data = ena_flow_hash_to_flow_type(hash_fields);
6541738cd3eSNetanel Belgazal 
6551738cd3eSNetanel Belgazal 	return 0;
6561738cd3eSNetanel Belgazal }
6571738cd3eSNetanel Belgazal 
ena_set_rss_hash(struct ena_com_dev * ena_dev,struct ethtool_rxnfc * cmd)6581738cd3eSNetanel Belgazal static int ena_set_rss_hash(struct ena_com_dev *ena_dev,
6591738cd3eSNetanel Belgazal 			    struct ethtool_rxnfc *cmd)
6601738cd3eSNetanel Belgazal {
6611738cd3eSNetanel Belgazal 	enum ena_admin_flow_hash_proto proto;
6621738cd3eSNetanel Belgazal 	u16 hash_fields;
6631738cd3eSNetanel Belgazal 
6641738cd3eSNetanel Belgazal 	switch (cmd->flow_type) {
6651738cd3eSNetanel Belgazal 	case TCP_V4_FLOW:
6661738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_TCP4;
6671738cd3eSNetanel Belgazal 		break;
6681738cd3eSNetanel Belgazal 	case UDP_V4_FLOW:
6691738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_UDP4;
6701738cd3eSNetanel Belgazal 		break;
6711738cd3eSNetanel Belgazal 	case TCP_V6_FLOW:
6721738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_TCP6;
6731738cd3eSNetanel Belgazal 		break;
6741738cd3eSNetanel Belgazal 	case UDP_V6_FLOW:
6751738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_UDP6;
6761738cd3eSNetanel Belgazal 		break;
6771738cd3eSNetanel Belgazal 	case IPV4_FLOW:
6781738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_IP4;
6791738cd3eSNetanel Belgazal 		break;
6801738cd3eSNetanel Belgazal 	case IPV6_FLOW:
6811738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_IP6;
6821738cd3eSNetanel Belgazal 		break;
6831738cd3eSNetanel Belgazal 	case ETHER_FLOW:
6841738cd3eSNetanel Belgazal 		proto = ENA_ADMIN_RSS_NOT_IP;
6851738cd3eSNetanel Belgazal 		break;
6861738cd3eSNetanel Belgazal 	case AH_V4_FLOW:
6871738cd3eSNetanel Belgazal 	case ESP_V4_FLOW:
6881738cd3eSNetanel Belgazal 	case AH_V6_FLOW:
6891738cd3eSNetanel Belgazal 	case ESP_V6_FLOW:
6901738cd3eSNetanel Belgazal 	case SCTP_V4_FLOW:
6911738cd3eSNetanel Belgazal 	case AH_ESP_V4_FLOW:
6921738cd3eSNetanel Belgazal 		return -EOPNOTSUPP;
6931738cd3eSNetanel Belgazal 	default:
6941738cd3eSNetanel Belgazal 		return -EINVAL;
6951738cd3eSNetanel Belgazal 	}
6961738cd3eSNetanel Belgazal 
6971738cd3eSNetanel Belgazal 	hash_fields = ena_flow_data_to_flow_hash(cmd->data);
6981738cd3eSNetanel Belgazal 
6991738cd3eSNetanel Belgazal 	return ena_com_fill_hash_ctrl(ena_dev, proto, hash_fields);
7001738cd3eSNetanel Belgazal }
7011738cd3eSNetanel Belgazal 
ena_set_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * info)7021738cd3eSNetanel Belgazal static int ena_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info)
7031738cd3eSNetanel Belgazal {
7041738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
7051738cd3eSNetanel Belgazal 	int rc = 0;
7061738cd3eSNetanel Belgazal 
7071738cd3eSNetanel Belgazal 	switch (info->cmd) {
7081738cd3eSNetanel Belgazal 	case ETHTOOL_SRXFH:
7091738cd3eSNetanel Belgazal 		rc = ena_set_rss_hash(adapter->ena_dev, info);
7101738cd3eSNetanel Belgazal 		break;
7111738cd3eSNetanel Belgazal 	case ETHTOOL_SRXCLSRLDEL:
7121738cd3eSNetanel Belgazal 	case ETHTOOL_SRXCLSRLINS:
7131738cd3eSNetanel Belgazal 	default:
7141738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev,
7151738cd3eSNetanel Belgazal 			  "Command parameter %d is not supported\n", info->cmd);
7161738cd3eSNetanel Belgazal 		rc = -EOPNOTSUPP;
7171738cd3eSNetanel Belgazal 	}
7181738cd3eSNetanel Belgazal 
719d1497638SNetanel Belgazal 	return rc;
7201738cd3eSNetanel Belgazal }
7211738cd3eSNetanel Belgazal 
ena_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * info,u32 * rules)7221738cd3eSNetanel Belgazal static int ena_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
7231738cd3eSNetanel Belgazal 			 u32 *rules)
7241738cd3eSNetanel Belgazal {
7251738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
7261738cd3eSNetanel Belgazal 	int rc = 0;
7271738cd3eSNetanel Belgazal 
7281738cd3eSNetanel Belgazal 	switch (info->cmd) {
7291738cd3eSNetanel Belgazal 	case ETHTOOL_GRXRINGS:
730faa615f9SSameeh Jubran 		info->data = adapter->num_io_queues;
7311738cd3eSNetanel Belgazal 		rc = 0;
7321738cd3eSNetanel Belgazal 		break;
7331738cd3eSNetanel Belgazal 	case ETHTOOL_GRXFH:
7341738cd3eSNetanel Belgazal 		rc = ena_get_rss_hash(adapter->ena_dev, info);
7351738cd3eSNetanel Belgazal 		break;
7361738cd3eSNetanel Belgazal 	case ETHTOOL_GRXCLSRLCNT:
7371738cd3eSNetanel Belgazal 	case ETHTOOL_GRXCLSRULE:
7381738cd3eSNetanel Belgazal 	case ETHTOOL_GRXCLSRLALL:
7391738cd3eSNetanel Belgazal 	default:
7401738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev,
7411738cd3eSNetanel Belgazal 			  "Command parameter %d is not supported\n", info->cmd);
7421738cd3eSNetanel Belgazal 		rc = -EOPNOTSUPP;
7431738cd3eSNetanel Belgazal 	}
7441738cd3eSNetanel Belgazal 
745d1497638SNetanel Belgazal 	return rc;
7461738cd3eSNetanel Belgazal }
7471738cd3eSNetanel Belgazal 
ena_get_rxfh_indir_size(struct net_device * netdev)7481738cd3eSNetanel Belgazal static u32 ena_get_rxfh_indir_size(struct net_device *netdev)
7491738cd3eSNetanel Belgazal {
7501738cd3eSNetanel Belgazal 	return ENA_RX_RSS_TABLE_SIZE;
7511738cd3eSNetanel Belgazal }
7521738cd3eSNetanel Belgazal 
ena_get_rxfh_key_size(struct net_device * netdev)7531738cd3eSNetanel Belgazal static u32 ena_get_rxfh_key_size(struct net_device *netdev)
7541738cd3eSNetanel Belgazal {
7551738cd3eSNetanel Belgazal 	return ENA_HASH_KEY_SIZE;
7561738cd3eSNetanel Belgazal }
7571738cd3eSNetanel Belgazal 
ena_indirection_table_set(struct ena_adapter * adapter,const u32 * indir)75877a651f5SArthur Kiyanovski static int ena_indirection_table_set(struct ena_adapter *adapter,
75977a651f5SArthur Kiyanovski 				     const u32 *indir)
76077a651f5SArthur Kiyanovski {
76177a651f5SArthur Kiyanovski 	struct ena_com_dev *ena_dev = adapter->ena_dev;
76277a651f5SArthur Kiyanovski 	int i, rc;
76377a651f5SArthur Kiyanovski 
76477a651f5SArthur Kiyanovski 	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
76577a651f5SArthur Kiyanovski 		rc = ena_com_indirect_table_fill_entry(ena_dev,
76677a651f5SArthur Kiyanovski 						       i,
76777a651f5SArthur Kiyanovski 						       ENA_IO_RXQ_IDX(indir[i]));
76877a651f5SArthur Kiyanovski 		if (unlikely(rc)) {
76977a651f5SArthur Kiyanovski 			netif_err(adapter, drv, adapter->netdev,
77077a651f5SArthur Kiyanovski 				  "Cannot fill indirect table (index is too large)\n");
77177a651f5SArthur Kiyanovski 			return rc;
77277a651f5SArthur Kiyanovski 		}
77377a651f5SArthur Kiyanovski 	}
77477a651f5SArthur Kiyanovski 
77577a651f5SArthur Kiyanovski 	rc = ena_com_indirect_table_set(ena_dev);
77677a651f5SArthur Kiyanovski 	if (rc) {
77777a651f5SArthur Kiyanovski 		netif_err(adapter, drv, adapter->netdev,
77877a651f5SArthur Kiyanovski 			  "Cannot set indirect table\n");
77977a651f5SArthur Kiyanovski 		return rc == -EPERM ? -EOPNOTSUPP : rc;
78077a651f5SArthur Kiyanovski 	}
78177a651f5SArthur Kiyanovski 	return rc;
78277a651f5SArthur Kiyanovski }
78377a651f5SArthur Kiyanovski 
ena_indirection_table_get(struct ena_adapter * adapter,u32 * indir)78492569fd2SArthur Kiyanovski static int ena_indirection_table_get(struct ena_adapter *adapter, u32 *indir)
78592569fd2SArthur Kiyanovski {
78692569fd2SArthur Kiyanovski 	struct ena_com_dev *ena_dev = adapter->ena_dev;
78792569fd2SArthur Kiyanovski 	int i, rc;
78892569fd2SArthur Kiyanovski 
78992569fd2SArthur Kiyanovski 	if (!indir)
79092569fd2SArthur Kiyanovski 		return 0;
79192569fd2SArthur Kiyanovski 
79292569fd2SArthur Kiyanovski 	rc = ena_com_indirect_table_get(ena_dev, indir);
79392569fd2SArthur Kiyanovski 	if (rc)
79492569fd2SArthur Kiyanovski 		return rc;
79592569fd2SArthur Kiyanovski 
79692569fd2SArthur Kiyanovski 	/* Our internal representation of the indices is: even indices
79792569fd2SArthur Kiyanovski 	 * for Tx and uneven indices for Rx. We need to convert the Rx
79892569fd2SArthur Kiyanovski 	 * indices to be consecutive
79992569fd2SArthur Kiyanovski 	 */
80092569fd2SArthur Kiyanovski 	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++)
80192569fd2SArthur Kiyanovski 		indir[i] = ENA_IO_RXQ_IDX_TO_COMBINED_IDX(indir[i]);
80292569fd2SArthur Kiyanovski 
80392569fd2SArthur Kiyanovski 	return rc;
80492569fd2SArthur Kiyanovski }
80592569fd2SArthur Kiyanovski 
ena_get_rxfh(struct net_device * netdev,u32 * indir,u8 * key,u8 * hfunc)8061738cd3eSNetanel Belgazal static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
8071738cd3eSNetanel Belgazal 			u8 *hfunc)
8081738cd3eSNetanel Belgazal {
8091738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
8101738cd3eSNetanel Belgazal 	enum ena_admin_hash_functions ena_func;
8111738cd3eSNetanel Belgazal 	u8 func;
8121738cd3eSNetanel Belgazal 	int rc;
8131738cd3eSNetanel Belgazal 
81492569fd2SArthur Kiyanovski 	rc = ena_indirection_table_get(adapter, indir);
8151738cd3eSNetanel Belgazal 	if (rc)
8161738cd3eSNetanel Belgazal 		return rc;
8171738cd3eSNetanel Belgazal 
8180c8923c0SSameeh Jubran 	/* We call this function in order to check if the device
8190c8923c0SSameeh Jubran 	 * supports getting/setting the hash function.
8200c8923c0SSameeh Jubran 	 */
821f66c2ea3SSameeh Jubran 	rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func);
8220c8923c0SSameeh Jubran 	if (rc) {
823cac7172fSSameeh Jubran 		if (rc == -EOPNOTSUPP)
8240c8923c0SSameeh Jubran 			rc = 0;
8250c8923c0SSameeh Jubran 
8260c8923c0SSameeh Jubran 		return rc;
8270c8923c0SSameeh Jubran 	}
8280c8923c0SSameeh Jubran 
829f66c2ea3SSameeh Jubran 	rc = ena_com_get_hash_key(adapter->ena_dev, key);
830f66c2ea3SSameeh Jubran 	if (rc)
831f66c2ea3SSameeh Jubran 		return rc;
832f66c2ea3SSameeh Jubran 
8331738cd3eSNetanel Belgazal 	switch (ena_func) {
8341738cd3eSNetanel Belgazal 	case ENA_ADMIN_TOEPLITZ:
8351738cd3eSNetanel Belgazal 		func = ETH_RSS_HASH_TOP;
8361738cd3eSNetanel Belgazal 		break;
8371738cd3eSNetanel Belgazal 	case ENA_ADMIN_CRC32:
838886d2089SSameeh Jubran 		func = ETH_RSS_HASH_CRC32;
8391738cd3eSNetanel Belgazal 		break;
8401738cd3eSNetanel Belgazal 	default:
8411738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev,
8421738cd3eSNetanel Belgazal 			  "Command parameter is not supported\n");
8431738cd3eSNetanel Belgazal 		return -EOPNOTSUPP;
8441738cd3eSNetanel Belgazal 	}
8451738cd3eSNetanel Belgazal 
8461738cd3eSNetanel Belgazal 	if (hfunc)
8471738cd3eSNetanel Belgazal 		*hfunc = func;
8481738cd3eSNetanel Belgazal 
849f66c2ea3SSameeh Jubran 	return 0;
8501738cd3eSNetanel Belgazal }
8511738cd3eSNetanel Belgazal 
ena_set_rxfh(struct net_device * netdev,const u32 * indir,const u8 * key,const u8 hfunc)8521738cd3eSNetanel Belgazal static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
8531738cd3eSNetanel Belgazal 			const u8 *key, const u8 hfunc)
8541738cd3eSNetanel Belgazal {
8551738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
8561738cd3eSNetanel Belgazal 	struct ena_com_dev *ena_dev = adapter->ena_dev;
857f66c2ea3SSameeh Jubran 	enum ena_admin_hash_functions func = 0;
85877a651f5SArthur Kiyanovski 	int rc;
8591738cd3eSNetanel Belgazal 
8601738cd3eSNetanel Belgazal 	if (indir) {
86177a651f5SArthur Kiyanovski 		rc = ena_indirection_table_set(adapter, indir);
86277a651f5SArthur Kiyanovski 		if (rc)
8631738cd3eSNetanel Belgazal 			return rc;
8641738cd3eSNetanel Belgazal 	}
8651738cd3eSNetanel Belgazal 
8661738cd3eSNetanel Belgazal 	switch (hfunc) {
867470793a7SArthur Kiyanovski 	case ETH_RSS_HASH_NO_CHANGE:
868470793a7SArthur Kiyanovski 		func = ena_com_get_current_hash_function(ena_dev);
869470793a7SArthur Kiyanovski 		break;
8701738cd3eSNetanel Belgazal 	case ETH_RSS_HASH_TOP:
8711738cd3eSNetanel Belgazal 		func = ENA_ADMIN_TOEPLITZ;
8721738cd3eSNetanel Belgazal 		break;
873886d2089SSameeh Jubran 	case ETH_RSS_HASH_CRC32:
8741738cd3eSNetanel Belgazal 		func = ENA_ADMIN_CRC32;
8751738cd3eSNetanel Belgazal 		break;
8761738cd3eSNetanel Belgazal 	default:
8771738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev, "Unsupported hfunc %d\n",
8781738cd3eSNetanel Belgazal 			  hfunc);
8791738cd3eSNetanel Belgazal 		return -EOPNOTSUPP;
8801738cd3eSNetanel Belgazal 	}
8811738cd3eSNetanel Belgazal 
882f66c2ea3SSameeh Jubran 	if (key || func) {
8831738cd3eSNetanel Belgazal 		rc = ena_com_fill_hash_function(ena_dev, func, key,
8841738cd3eSNetanel Belgazal 						ENA_HASH_KEY_SIZE,
8851738cd3eSNetanel Belgazal 						0xFFFFFFFF);
8861738cd3eSNetanel Belgazal 		if (unlikely(rc)) {
8871738cd3eSNetanel Belgazal 			netif_err(adapter, drv, netdev, "Cannot fill key\n");
8881738cd3eSNetanel Belgazal 			return rc == -EPERM ? -EOPNOTSUPP : rc;
8891738cd3eSNetanel Belgazal 		}
8901738cd3eSNetanel Belgazal 	}
8911738cd3eSNetanel Belgazal 
8921738cd3eSNetanel Belgazal 	return 0;
8931738cd3eSNetanel Belgazal }
8941738cd3eSNetanel Belgazal 
ena_get_channels(struct net_device * netdev,struct ethtool_channels * channels)8951738cd3eSNetanel Belgazal static void ena_get_channels(struct net_device *netdev,
8961738cd3eSNetanel Belgazal 			     struct ethtool_channels *channels)
8971738cd3eSNetanel Belgazal {
8981738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
8991738cd3eSNetanel Belgazal 
900736ce3f4SSameeh Jubran 	channels->max_combined = adapter->max_num_io_queues;
9019a037b06SSameeh Jubran 	channels->combined_count = adapter->num_io_queues;
9021738cd3eSNetanel Belgazal }
9031738cd3eSNetanel Belgazal 
ena_set_channels(struct net_device * netdev,struct ethtool_channels * channels)9042413ea97SSameeh Jubran static int ena_set_channels(struct net_device *netdev,
9052413ea97SSameeh Jubran 			    struct ethtool_channels *channels)
9062413ea97SSameeh Jubran {
9072413ea97SSameeh Jubran 	struct ena_adapter *adapter = netdev_priv(netdev);
9082413ea97SSameeh Jubran 	u32 count = channels->combined_count;
9092413ea97SSameeh Jubran 	/* The check for max value is already done in ethtool */
9107aa6dc35SLorenzo Bianconi 	if (count < ENA_MIN_NUM_IO_QUEUES)
9112413ea97SSameeh Jubran 		return -EINVAL;
9122413ea97SSameeh Jubran 
9137aa6dc35SLorenzo Bianconi 	if (!ena_xdp_legal_queue_count(adapter, count)) {
9147aa6dc35SLorenzo Bianconi 		if (ena_xdp_present(adapter))
9157aa6dc35SLorenzo Bianconi 			return -EINVAL;
9167aa6dc35SLorenzo Bianconi 
9177aa6dc35SLorenzo Bianconi 		xdp_clear_features_flag(netdev);
9187aa6dc35SLorenzo Bianconi 	} else {
9197aa6dc35SLorenzo Bianconi 		xdp_set_features_flag(netdev,
9207aa6dc35SLorenzo Bianconi 				      NETDEV_XDP_ACT_BASIC |
9217aa6dc35SLorenzo Bianconi 				      NETDEV_XDP_ACT_REDIRECT);
9227aa6dc35SLorenzo Bianconi 	}
9237aa6dc35SLorenzo Bianconi 
9242413ea97SSameeh Jubran 	return ena_update_queue_count(adapter, count);
9252413ea97SSameeh Jubran }
9262413ea97SSameeh Jubran 
ena_get_tunable(struct net_device * netdev,const struct ethtool_tunable * tuna,void * data)9271738cd3eSNetanel Belgazal static int ena_get_tunable(struct net_device *netdev,
9281738cd3eSNetanel Belgazal 			   const struct ethtool_tunable *tuna, void *data)
9291738cd3eSNetanel Belgazal {
9301738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
9311738cd3eSNetanel Belgazal 	int ret = 0;
9321738cd3eSNetanel Belgazal 
9331738cd3eSNetanel Belgazal 	switch (tuna->id) {
9341738cd3eSNetanel Belgazal 	case ETHTOOL_RX_COPYBREAK:
9351738cd3eSNetanel Belgazal 		*(u32 *)data = adapter->rx_copybreak;
9361738cd3eSNetanel Belgazal 		break;
9371738cd3eSNetanel Belgazal 	default:
9381738cd3eSNetanel Belgazal 		ret = -EINVAL;
9391738cd3eSNetanel Belgazal 		break;
9401738cd3eSNetanel Belgazal 	}
9411738cd3eSNetanel Belgazal 
9421738cd3eSNetanel Belgazal 	return ret;
9431738cd3eSNetanel Belgazal }
9441738cd3eSNetanel Belgazal 
ena_set_tunable(struct net_device * netdev,const struct ethtool_tunable * tuna,const void * data)9451738cd3eSNetanel Belgazal static int ena_set_tunable(struct net_device *netdev,
9461738cd3eSNetanel Belgazal 			   const struct ethtool_tunable *tuna,
9471738cd3eSNetanel Belgazal 			   const void *data)
9481738cd3eSNetanel Belgazal {
9491738cd3eSNetanel Belgazal 	struct ena_adapter *adapter = netdev_priv(netdev);
9501738cd3eSNetanel Belgazal 	int ret = 0;
9511738cd3eSNetanel Belgazal 	u32 len;
9521738cd3eSNetanel Belgazal 
9531738cd3eSNetanel Belgazal 	switch (tuna->id) {
9541738cd3eSNetanel Belgazal 	case ETHTOOL_RX_COPYBREAK:
9551738cd3eSNetanel Belgazal 		len = *(u32 *)data;
956c7062aaeSDavid Arinzon 		ret = ena_set_rx_copybreak(adapter, len);
9571738cd3eSNetanel Belgazal 		break;
9581738cd3eSNetanel Belgazal 	default:
9591738cd3eSNetanel Belgazal 		ret = -EINVAL;
9601738cd3eSNetanel Belgazal 		break;
9611738cd3eSNetanel Belgazal 	}
9621738cd3eSNetanel Belgazal 
9631738cd3eSNetanel Belgazal 	return ret;
9641738cd3eSNetanel Belgazal }
9651738cd3eSNetanel Belgazal 
9661738cd3eSNetanel Belgazal static const struct ethtool_ops ena_ethtool_ops = {
9678e4f90caSJakub Kicinski 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
9688e4f90caSJakub Kicinski 				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
969060cdac2SShay Agroskin 	.supported_ring_params	= ETHTOOL_RING_USE_TX_PUSH_BUF_LEN |
970060cdac2SShay Agroskin 				  ETHTOOL_RING_USE_TX_PUSH,
9711738cd3eSNetanel Belgazal 	.get_link_ksettings	= ena_get_link_ksettings,
9721738cd3eSNetanel Belgazal 	.get_drvinfo		= ena_get_drvinfo,
9731738cd3eSNetanel Belgazal 	.get_msglevel		= ena_get_msglevel,
9741738cd3eSNetanel Belgazal 	.set_msglevel		= ena_set_msglevel,
9751738cd3eSNetanel Belgazal 	.get_link		= ethtool_op_get_link,
9761738cd3eSNetanel Belgazal 	.get_coalesce		= ena_get_coalesce,
9771738cd3eSNetanel Belgazal 	.set_coalesce		= ena_set_coalesce,
9781738cd3eSNetanel Belgazal 	.get_ringparam		= ena_get_ringparam,
979eece4d2aSSameeh Jubran 	.set_ringparam		= ena_set_ringparam,
9801738cd3eSNetanel Belgazal 	.get_sset_count         = ena_get_sset_count,
981713865daSSameeh Jubran 	.get_strings		= ena_get_ethtool_strings,
9821738cd3eSNetanel Belgazal 	.get_ethtool_stats      = ena_get_ethtool_stats,
9831738cd3eSNetanel Belgazal 	.get_rxnfc		= ena_get_rxnfc,
9841738cd3eSNetanel Belgazal 	.set_rxnfc		= ena_set_rxnfc,
9851738cd3eSNetanel Belgazal 	.get_rxfh_indir_size    = ena_get_rxfh_indir_size,
9861738cd3eSNetanel Belgazal 	.get_rxfh_key_size	= ena_get_rxfh_key_size,
9871738cd3eSNetanel Belgazal 	.get_rxfh		= ena_get_rxfh,
9881738cd3eSNetanel Belgazal 	.set_rxfh		= ena_set_rxfh,
9891738cd3eSNetanel Belgazal 	.get_channels		= ena_get_channels,
9902413ea97SSameeh Jubran 	.set_channels		= ena_set_channels,
9911738cd3eSNetanel Belgazal 	.get_tunable		= ena_get_tunable,
9921738cd3eSNetanel Belgazal 	.set_tunable		= ena_set_tunable,
993cf6d17fdSArthur Kiyanovski 	.get_ts_info            = ethtool_op_get_ts_info,
9941738cd3eSNetanel Belgazal };
9951738cd3eSNetanel Belgazal 
ena_set_ethtool_ops(struct net_device * netdev)9961738cd3eSNetanel Belgazal void ena_set_ethtool_ops(struct net_device *netdev)
9971738cd3eSNetanel Belgazal {
9981738cd3eSNetanel Belgazal 	netdev->ethtool_ops = &ena_ethtool_ops;
9991738cd3eSNetanel Belgazal }
10001738cd3eSNetanel Belgazal 
ena_dump_stats_ex(struct ena_adapter * adapter,u8 * buf)10011738cd3eSNetanel Belgazal static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf)
10021738cd3eSNetanel Belgazal {
10031738cd3eSNetanel Belgazal 	struct net_device *netdev = adapter->netdev;
10041738cd3eSNetanel Belgazal 	u8 *strings_buf;
10051738cd3eSNetanel Belgazal 	u64 *data_buf;
10061738cd3eSNetanel Belgazal 	int strings_num;
10071738cd3eSNetanel Belgazal 	int i, rc;
10081738cd3eSNetanel Belgazal 
1009713865daSSameeh Jubran 	strings_num = ena_get_sw_stats_count(adapter);
10101738cd3eSNetanel Belgazal 	if (strings_num <= 0) {
10111738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev, "Can't get stats num\n");
10121738cd3eSNetanel Belgazal 		return;
10131738cd3eSNetanel Belgazal 	}
10141738cd3eSNetanel Belgazal 
1015a86854d0SKees Cook 	strings_buf = devm_kcalloc(&adapter->pdev->dev,
1016a86854d0SKees Cook 				   ETH_GSTRING_LEN, strings_num,
10171738cd3eSNetanel Belgazal 				   GFP_ATOMIC);
10181738cd3eSNetanel Belgazal 	if (!strings_buf) {
10191738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev,
1020bf2746e8SShay Agroskin 			  "Failed to allocate strings_buf\n");
10211738cd3eSNetanel Belgazal 		return;
10221738cd3eSNetanel Belgazal 	}
10231738cd3eSNetanel Belgazal 
1024a86854d0SKees Cook 	data_buf = devm_kcalloc(&adapter->pdev->dev,
1025a86854d0SKees Cook 				strings_num, sizeof(u64),
10261738cd3eSNetanel Belgazal 				GFP_ATOMIC);
10271738cd3eSNetanel Belgazal 	if (!data_buf) {
10281738cd3eSNetanel Belgazal 		netif_err(adapter, drv, netdev,
1029713865daSSameeh Jubran 			  "Failed to allocate data buf\n");
10301738cd3eSNetanel Belgazal 		devm_kfree(&adapter->pdev->dev, strings_buf);
10311738cd3eSNetanel Belgazal 		return;
10321738cd3eSNetanel Belgazal 	}
10331738cd3eSNetanel Belgazal 
1034713865daSSameeh Jubran 	ena_get_strings(adapter, strings_buf, false);
1035713865daSSameeh Jubran 	ena_get_stats(adapter, data_buf, false);
10361738cd3eSNetanel Belgazal 
10371738cd3eSNetanel Belgazal 	/* If there is a buffer, dump stats, otherwise print them to dmesg */
10381738cd3eSNetanel Belgazal 	if (buf)
10391738cd3eSNetanel Belgazal 		for (i = 0; i < strings_num; i++) {
10401738cd3eSNetanel Belgazal 			rc = snprintf(buf, ETH_GSTRING_LEN + sizeof(u64),
10411738cd3eSNetanel Belgazal 				      "%s %llu\n",
10421738cd3eSNetanel Belgazal 				      strings_buf + i * ETH_GSTRING_LEN,
10431738cd3eSNetanel Belgazal 				      data_buf[i]);
10441738cd3eSNetanel Belgazal 			buf += rc;
10451738cd3eSNetanel Belgazal 		}
10461738cd3eSNetanel Belgazal 	else
10471738cd3eSNetanel Belgazal 		for (i = 0; i < strings_num; i++)
10481738cd3eSNetanel Belgazal 			netif_err(adapter, drv, netdev, "%s: %llu\n",
10491738cd3eSNetanel Belgazal 				  strings_buf + i * ETH_GSTRING_LEN,
10501738cd3eSNetanel Belgazal 				  data_buf[i]);
10511738cd3eSNetanel Belgazal 
10521738cd3eSNetanel Belgazal 	devm_kfree(&adapter->pdev->dev, strings_buf);
10531738cd3eSNetanel Belgazal 	devm_kfree(&adapter->pdev->dev, data_buf);
10541738cd3eSNetanel Belgazal }
10551738cd3eSNetanel Belgazal 
ena_dump_stats_to_buf(struct ena_adapter * adapter,u8 * buf)10561738cd3eSNetanel Belgazal void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf)
10571738cd3eSNetanel Belgazal {
10581738cd3eSNetanel Belgazal 	if (!buf)
10591738cd3eSNetanel Belgazal 		return;
10601738cd3eSNetanel Belgazal 
10611738cd3eSNetanel Belgazal 	ena_dump_stats_ex(adapter, buf);
10621738cd3eSNetanel Belgazal }
10631738cd3eSNetanel Belgazal 
ena_dump_stats_to_dmesg(struct ena_adapter * adapter)10641738cd3eSNetanel Belgazal void ena_dump_stats_to_dmesg(struct ena_adapter *adapter)
10651738cd3eSNetanel Belgazal {
10661738cd3eSNetanel Belgazal 	ena_dump_stats_ex(adapter, NULL);
10671738cd3eSNetanel Belgazal }
1068