xref: /openbmc/linux/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24863dea3SSunil Goutham /*
34863dea3SSunil Goutham  * Copyright (C) 2015 Cavium, Inc.
44863dea3SSunil Goutham  */
54863dea3SSunil Goutham 
64863dea3SSunil Goutham /* ETHTOOL Support for VNIC_VF Device*/
74863dea3SSunil Goutham 
8cc69837fSJakub Kicinski #include <linux/ethtool.h>
94863dea3SSunil Goutham #include <linux/pci.h>
104a875509SSunil Goutham #include <linux/net_tstamp.h>
114863dea3SSunil Goutham 
124863dea3SSunil Goutham #include "nic_reg.h"
134863dea3SSunil Goutham #include "nic.h"
144863dea3SSunil Goutham #include "nicvf_queues.h"
154863dea3SSunil Goutham #include "q_struct.h"
164863dea3SSunil Goutham #include "thunder_bgx.h"
174a875509SSunil Goutham #include "../common/cavium_ptp.h"
184863dea3SSunil Goutham 
196b9e6547SVadim Lomovtsev #define DRV_NAME	"nicvf"
204863dea3SSunil Goutham 
214863dea3SSunil Goutham struct nicvf_stat {
224863dea3SSunil Goutham 	char name[ETH_GSTRING_LEN];
234863dea3SSunil Goutham 	unsigned int index;
244863dea3SSunil Goutham };
254863dea3SSunil Goutham 
264863dea3SSunil Goutham #define NICVF_HW_STAT(stat) { \
274863dea3SSunil Goutham 	.name = #stat, \
284863dea3SSunil Goutham 	.index = offsetof(struct nicvf_hw_stats, stat) / sizeof(u64), \
294863dea3SSunil Goutham }
304863dea3SSunil Goutham 
314863dea3SSunil Goutham #define NICVF_DRV_STAT(stat) { \
324863dea3SSunil Goutham 	.name = #stat, \
334863dea3SSunil Goutham 	.index = offsetof(struct nicvf_drv_stats, stat) / sizeof(u64), \
344863dea3SSunil Goutham }
354863dea3SSunil Goutham 
364863dea3SSunil Goutham static const struct nicvf_stat nicvf_hw_stats[] = {
37a2dc5dedSSunil Goutham 	NICVF_HW_STAT(rx_bytes),
38964cb69bSSunil Goutham 	NICVF_HW_STAT(rx_frames),
39a2dc5dedSSunil Goutham 	NICVF_HW_STAT(rx_ucast_frames),
40a2dc5dedSSunil Goutham 	NICVF_HW_STAT(rx_bcast_frames),
41a2dc5dedSSunil Goutham 	NICVF_HW_STAT(rx_mcast_frames),
42964cb69bSSunil Goutham 	NICVF_HW_STAT(rx_drops),
434863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_red),
444863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_red_bytes),
454863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_overrun),
464863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_overrun_bytes),
474863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_bcast),
484863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_mcast),
494863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_l3_bcast),
504863dea3SSunil Goutham 	NICVF_HW_STAT(rx_drop_l3_mcast),
51964cb69bSSunil Goutham 	NICVF_HW_STAT(rx_fcs_errors),
52964cb69bSSunil Goutham 	NICVF_HW_STAT(rx_l2_errors),
53964cb69bSSunil Goutham 	NICVF_HW_STAT(tx_bytes),
54964cb69bSSunil Goutham 	NICVF_HW_STAT(tx_frames),
55964cb69bSSunil Goutham 	NICVF_HW_STAT(tx_ucast_frames),
56964cb69bSSunil Goutham 	NICVF_HW_STAT(tx_bcast_frames),
57964cb69bSSunil Goutham 	NICVF_HW_STAT(tx_mcast_frames),
58964cb69bSSunil Goutham 	NICVF_HW_STAT(tx_drops),
594863dea3SSunil Goutham };
604863dea3SSunil Goutham 
614863dea3SSunil Goutham static const struct nicvf_stat nicvf_drv_stats[] = {
62964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_bgx_truncated_pkts),
63964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_jabber_errs),
64964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_fcs_errs),
65964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_bgx_errs),
66964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_prel2_errs),
67964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l2_hdr_malformed),
68964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_oversize),
69964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_undersize),
70964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l2_len_mismatch),
71964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l2_pclp),
72964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_ip_ver_errs),
73964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_ip_csum_errs),
74964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_ip_hdr_malformed),
75964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_ip_payload_malformed),
76964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_ip_ttl_errs),
77964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l3_pclp),
78964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l4_malformed),
79964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l4_csum_errs),
80964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_udp_len_errs),
81964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l4_port_errs),
82964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_tcp_flag_errs),
83964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_tcp_offset_errs),
84964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_l4_pclp),
85964cb69bSSunil Goutham 	NICVF_DRV_STAT(rx_truncated_pkts),
86964cb69bSSunil Goutham 
87964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_desc_fault),
88964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_hdr_cons_err),
89964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_subdesc_err),
90964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_max_size_exceeded),
91964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_imm_size_oflow),
92964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_data_seq_err),
93964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_mem_seq_err),
94964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_lock_viol),
95964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_data_fault),
96964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_tstmp_conflict),
97964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_tstmp_timeout),
98964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_mem_fault),
99964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_csum_overlap),
100964cb69bSSunil Goutham 	NICVF_DRV_STAT(tx_csum_overflow),
101964cb69bSSunil Goutham 
1024863dea3SSunil Goutham 	NICVF_DRV_STAT(tx_tso),
103a05d4845SThanneeru Srinivasulu 	NICVF_DRV_STAT(tx_timeout),
10474840b83SSunil Goutham 	NICVF_DRV_STAT(txq_stop),
10574840b83SSunil Goutham 	NICVF_DRV_STAT(txq_wake),
1065836b442SSunil Goutham 	NICVF_DRV_STAT(rcv_buffer_alloc_failures),
1075836b442SSunil Goutham 	NICVF_DRV_STAT(page_alloc),
1084863dea3SSunil Goutham };
1094863dea3SSunil Goutham 
1104863dea3SSunil Goutham static const struct nicvf_stat nicvf_queue_stats[] = {
1114863dea3SSunil Goutham 	{ "bytes", 0 },
1124863dea3SSunil Goutham 	{ "frames", 1 },
1134863dea3SSunil Goutham };
1144863dea3SSunil Goutham 
1154863dea3SSunil Goutham static const unsigned int nicvf_n_hw_stats = ARRAY_SIZE(nicvf_hw_stats);
1164863dea3SSunil Goutham static const unsigned int nicvf_n_drv_stats = ARRAY_SIZE(nicvf_drv_stats);
1174863dea3SSunil Goutham static const unsigned int nicvf_n_queue_stats = ARRAY_SIZE(nicvf_queue_stats);
1184863dea3SSunil Goutham 
nicvf_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)119bfd8d977SPhilippe Reynes static int nicvf_get_link_ksettings(struct net_device *netdev,
120bfd8d977SPhilippe Reynes 				    struct ethtool_link_ksettings *cmd)
1214863dea3SSunil Goutham {
1224863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
123bfd8d977SPhilippe Reynes 	u32 supported, advertising;
1244863dea3SSunil Goutham 
125bfd8d977SPhilippe Reynes 	supported = 0;
126bfd8d977SPhilippe Reynes 	advertising = 0;
1270b72a9a1SSunil Goutham 
1280b72a9a1SSunil Goutham 	if (!nic->link_up) {
129bfd8d977SPhilippe Reynes 		cmd->base.duplex = DUPLEX_UNKNOWN;
130bfd8d977SPhilippe Reynes 		cmd->base.speed = SPEED_UNKNOWN;
1310b72a9a1SSunil Goutham 		return 0;
1320b72a9a1SSunil Goutham 	}
1330b72a9a1SSunil Goutham 
1341cc70259SThanneeru Srinivasulu 	switch (nic->speed) {
1351cc70259SThanneeru Srinivasulu 	case SPEED_1000:
136bfd8d977SPhilippe Reynes 		cmd->base.port = PORT_MII | PORT_TP;
137bfd8d977SPhilippe Reynes 		cmd->base.autoneg = AUTONEG_ENABLE;
138bfd8d977SPhilippe Reynes 		supported |= SUPPORTED_MII | SUPPORTED_TP;
139bfd8d977SPhilippe Reynes 		supported |= SUPPORTED_1000baseT_Full |
1401cc70259SThanneeru Srinivasulu 				  SUPPORTED_1000baseT_Half |
1411cc70259SThanneeru Srinivasulu 				  SUPPORTED_100baseT_Full  |
1421cc70259SThanneeru Srinivasulu 				  SUPPORTED_100baseT_Half  |
1431cc70259SThanneeru Srinivasulu 				  SUPPORTED_10baseT_Full   |
1441cc70259SThanneeru Srinivasulu 				  SUPPORTED_10baseT_Half;
145bfd8d977SPhilippe Reynes 		supported |= SUPPORTED_Autoneg;
146bfd8d977SPhilippe Reynes 		advertising |= ADVERTISED_1000baseT_Full |
1471cc70259SThanneeru Srinivasulu 				    ADVERTISED_1000baseT_Half |
1481cc70259SThanneeru Srinivasulu 				    ADVERTISED_100baseT_Full  |
1491cc70259SThanneeru Srinivasulu 				    ADVERTISED_100baseT_Half  |
1501cc70259SThanneeru Srinivasulu 				    ADVERTISED_10baseT_Full   |
1511cc70259SThanneeru Srinivasulu 				    ADVERTISED_10baseT_Half;
1521cc70259SThanneeru Srinivasulu 		break;
1531cc70259SThanneeru Srinivasulu 	case SPEED_10000:
1541cc70259SThanneeru Srinivasulu 		if (nic->mac_type == BGX_MODE_RXAUI) {
155bfd8d977SPhilippe Reynes 			cmd->base.port = PORT_TP;
156bfd8d977SPhilippe Reynes 			supported |= SUPPORTED_TP;
1574863dea3SSunil Goutham 		} else {
158bfd8d977SPhilippe Reynes 			cmd->base.port = PORT_FIBRE;
159bfd8d977SPhilippe Reynes 			supported |= SUPPORTED_FIBRE;
1601cc70259SThanneeru Srinivasulu 		}
161bfd8d977SPhilippe Reynes 		cmd->base.autoneg = AUTONEG_DISABLE;
162bfd8d977SPhilippe Reynes 		supported |= SUPPORTED_10000baseT_Full;
1631cc70259SThanneeru Srinivasulu 		break;
1641cc70259SThanneeru Srinivasulu 	case SPEED_40000:
165bfd8d977SPhilippe Reynes 		cmd->base.port = PORT_FIBRE;
166bfd8d977SPhilippe Reynes 		cmd->base.autoneg = AUTONEG_DISABLE;
167bfd8d977SPhilippe Reynes 		supported |= SUPPORTED_FIBRE;
168bfd8d977SPhilippe Reynes 		supported |= SUPPORTED_40000baseCR4_Full;
1691cc70259SThanneeru Srinivasulu 		break;
1704863dea3SSunil Goutham 	}
171bfd8d977SPhilippe Reynes 	cmd->base.duplex = nic->duplex;
172bfd8d977SPhilippe Reynes 	cmd->base.speed = nic->speed;
173bfd8d977SPhilippe Reynes 
174bfd8d977SPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
175bfd8d977SPhilippe Reynes 						supported);
176bfd8d977SPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
177bfd8d977SPhilippe Reynes 						advertising);
1784863dea3SSunil Goutham 
1794863dea3SSunil Goutham 	return 0;
1804863dea3SSunil Goutham }
1814863dea3SSunil Goutham 
nicvf_get_link(struct net_device * netdev)1820b72a9a1SSunil Goutham static u32 nicvf_get_link(struct net_device *netdev)
1830b72a9a1SSunil Goutham {
1840b72a9a1SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
1850b72a9a1SSunil Goutham 
1860b72a9a1SSunil Goutham 	return nic->link_up;
1870b72a9a1SSunil Goutham }
1880b72a9a1SSunil Goutham 
nicvf_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)1894863dea3SSunil Goutham static void nicvf_get_drvinfo(struct net_device *netdev,
1904863dea3SSunil Goutham 			      struct ethtool_drvinfo *info)
1914863dea3SSunil Goutham {
1924863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
1934863dea3SSunil Goutham 
194f029c781SWolfram Sang 	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
195f029c781SWolfram Sang 	strscpy(info->bus_info, pci_name(nic->pdev), sizeof(info->bus_info));
1964863dea3SSunil Goutham }
1974863dea3SSunil Goutham 
nicvf_get_msglevel(struct net_device * netdev)1984863dea3SSunil Goutham static u32 nicvf_get_msglevel(struct net_device *netdev)
1994863dea3SSunil Goutham {
2004863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
2014863dea3SSunil Goutham 
2024863dea3SSunil Goutham 	return nic->msg_enable;
2034863dea3SSunil Goutham }
2044863dea3SSunil Goutham 
nicvf_set_msglevel(struct net_device * netdev,u32 lvl)2054863dea3SSunil Goutham static void nicvf_set_msglevel(struct net_device *netdev, u32 lvl)
2064863dea3SSunil Goutham {
2074863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
2084863dea3SSunil Goutham 
2094863dea3SSunil Goutham 	nic->msg_enable = lvl;
2104863dea3SSunil Goutham }
2114863dea3SSunil Goutham 
nicvf_get_qset_strings(struct nicvf * nic,u8 ** data,int qset)21292dc8769SSunil Goutham static void nicvf_get_qset_strings(struct nicvf *nic, u8 **data, int qset)
21392dc8769SSunil Goutham {
21492dc8769SSunil Goutham 	int stats, qidx;
21592dc8769SSunil Goutham 	int start_qidx = qset * MAX_RCV_QUEUES_PER_QS;
21692dc8769SSunil Goutham 
21792dc8769SSunil Goutham 	for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
21892dc8769SSunil Goutham 		for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
21992dc8769SSunil Goutham 			sprintf(*data, "rxq%d: %s", qidx + start_qidx,
22092dc8769SSunil Goutham 				nicvf_queue_stats[stats].name);
22192dc8769SSunil Goutham 			*data += ETH_GSTRING_LEN;
22292dc8769SSunil Goutham 		}
22392dc8769SSunil Goutham 	}
22492dc8769SSunil Goutham 
22592dc8769SSunil Goutham 	for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
22692dc8769SSunil Goutham 		for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
22792dc8769SSunil Goutham 			sprintf(*data, "txq%d: %s", qidx + start_qidx,
22892dc8769SSunil Goutham 				nicvf_queue_stats[stats].name);
22992dc8769SSunil Goutham 			*data += ETH_GSTRING_LEN;
23092dc8769SSunil Goutham 		}
23192dc8769SSunil Goutham 	}
23292dc8769SSunil Goutham }
23392dc8769SSunil Goutham 
nicvf_get_strings(struct net_device * netdev,u32 sset,u8 * data)2344863dea3SSunil Goutham static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
2354863dea3SSunil Goutham {
236c62cd3c4SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
23792dc8769SSunil Goutham 	int stats;
23892dc8769SSunil Goutham 	int sqs;
2394863dea3SSunil Goutham 
2404863dea3SSunil Goutham 	if (sset != ETH_SS_STATS)
2414863dea3SSunil Goutham 		return;
2424863dea3SSunil Goutham 
2434863dea3SSunil Goutham 	for (stats = 0; stats < nicvf_n_hw_stats; stats++) {
2444863dea3SSunil Goutham 		memcpy(data, nicvf_hw_stats[stats].name, ETH_GSTRING_LEN);
2454863dea3SSunil Goutham 		data += ETH_GSTRING_LEN;
2464863dea3SSunil Goutham 	}
2474863dea3SSunil Goutham 
2484863dea3SSunil Goutham 	for (stats = 0; stats < nicvf_n_drv_stats; stats++) {
2494863dea3SSunil Goutham 		memcpy(data, nicvf_drv_stats[stats].name, ETH_GSTRING_LEN);
2504863dea3SSunil Goutham 		data += ETH_GSTRING_LEN;
2514863dea3SSunil Goutham 	}
2524863dea3SSunil Goutham 
25392dc8769SSunil Goutham 	nicvf_get_qset_strings(nic, &data, 0);
2544863dea3SSunil Goutham 
25592dc8769SSunil Goutham 	for (sqs = 0; sqs < nic->sqs_count; sqs++) {
25692dc8769SSunil Goutham 		if (!nic->snicvf[sqs])
25792dc8769SSunil Goutham 			continue;
25892dc8769SSunil Goutham 		nicvf_get_qset_strings(nic->snicvf[sqs], &data, sqs + 1);
2594863dea3SSunil Goutham 	}
2604863dea3SSunil Goutham 
2614863dea3SSunil Goutham 	for (stats = 0; stats < BGX_RX_STATS_COUNT; stats++) {
2624863dea3SSunil Goutham 		sprintf(data, "bgx_rxstat%d: ", stats);
2634863dea3SSunil Goutham 		data += ETH_GSTRING_LEN;
2644863dea3SSunil Goutham 	}
2654863dea3SSunil Goutham 
2664863dea3SSunil Goutham 	for (stats = 0; stats < BGX_TX_STATS_COUNT; stats++) {
2674863dea3SSunil Goutham 		sprintf(data, "bgx_txstat%d: ", stats);
2684863dea3SSunil Goutham 		data += ETH_GSTRING_LEN;
2694863dea3SSunil Goutham 	}
2704863dea3SSunil Goutham }
2714863dea3SSunil Goutham 
nicvf_get_sset_count(struct net_device * netdev,int sset)2724863dea3SSunil Goutham static int nicvf_get_sset_count(struct net_device *netdev, int sset)
2734863dea3SSunil Goutham {
274c62cd3c4SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
27592dc8769SSunil Goutham 	int qstats_count;
27692dc8769SSunil Goutham 	int sqs;
277c62cd3c4SSunil Goutham 
2784863dea3SSunil Goutham 	if (sset != ETH_SS_STATS)
2794863dea3SSunil Goutham 		return -EINVAL;
2804863dea3SSunil Goutham 
28192dc8769SSunil Goutham 	qstats_count = nicvf_n_queue_stats *
28292dc8769SSunil Goutham 		       (nic->qs->rq_cnt + nic->qs->sq_cnt);
28392dc8769SSunil Goutham 	for (sqs = 0; sqs < nic->sqs_count; sqs++) {
28492dc8769SSunil Goutham 		struct nicvf *snic;
28592dc8769SSunil Goutham 
28692dc8769SSunil Goutham 		snic = nic->snicvf[sqs];
28792dc8769SSunil Goutham 		if (!snic)
28892dc8769SSunil Goutham 			continue;
28992dc8769SSunil Goutham 		qstats_count += nicvf_n_queue_stats *
29092dc8769SSunil Goutham 				(snic->qs->rq_cnt + snic->qs->sq_cnt);
29192dc8769SSunil Goutham 	}
29292dc8769SSunil Goutham 
2934863dea3SSunil Goutham 	return nicvf_n_hw_stats + nicvf_n_drv_stats +
29492dc8769SSunil Goutham 		qstats_count +
2954863dea3SSunil Goutham 		BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT;
2964863dea3SSunil Goutham }
2974863dea3SSunil Goutham 
nicvf_get_qset_stats(struct nicvf * nic,struct ethtool_stats * stats,u64 ** data)29892dc8769SSunil Goutham static void nicvf_get_qset_stats(struct nicvf *nic,
29992dc8769SSunil Goutham 				 struct ethtool_stats *stats, u64 **data)
30092dc8769SSunil Goutham {
30192dc8769SSunil Goutham 	int stat, qidx;
30292dc8769SSunil Goutham 
30392dc8769SSunil Goutham 	if (!nic)
30492dc8769SSunil Goutham 		return;
30592dc8769SSunil Goutham 
30692dc8769SSunil Goutham 	for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
30792dc8769SSunil Goutham 		nicvf_update_rq_stats(nic, qidx);
30892dc8769SSunil Goutham 		for (stat = 0; stat < nicvf_n_queue_stats; stat++)
30992dc8769SSunil Goutham 			*((*data)++) = ((u64 *)&nic->qs->rq[qidx].stats)
31092dc8769SSunil Goutham 					[nicvf_queue_stats[stat].index];
31192dc8769SSunil Goutham 	}
31292dc8769SSunil Goutham 
31392dc8769SSunil Goutham 	for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
31492dc8769SSunil Goutham 		nicvf_update_sq_stats(nic, qidx);
31592dc8769SSunil Goutham 		for (stat = 0; stat < nicvf_n_queue_stats; stat++)
31692dc8769SSunil Goutham 			*((*data)++) = ((u64 *)&nic->qs->sq[qidx].stats)
31792dc8769SSunil Goutham 					[nicvf_queue_stats[stat].index];
31892dc8769SSunil Goutham 	}
31992dc8769SSunil Goutham }
32092dc8769SSunil Goutham 
nicvf_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)3214863dea3SSunil Goutham static void nicvf_get_ethtool_stats(struct net_device *netdev,
3224863dea3SSunil Goutham 				    struct ethtool_stats *stats, u64 *data)
3234863dea3SSunil Goutham {
3244863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
325964cb69bSSunil Goutham 	int stat, tmp_stats;
326964cb69bSSunil Goutham 	int sqs, cpu;
3274863dea3SSunil Goutham 
3284863dea3SSunil Goutham 	nicvf_update_stats(nic);
3294863dea3SSunil Goutham 
3304863dea3SSunil Goutham 	/* Update LMAC stats */
3314863dea3SSunil Goutham 	nicvf_update_lmac_stats(nic);
3324863dea3SSunil Goutham 
3334863dea3SSunil Goutham 	for (stat = 0; stat < nicvf_n_hw_stats; stat++)
334a2dc5dedSSunil Goutham 		*(data++) = ((u64 *)&nic->hw_stats)
3354863dea3SSunil Goutham 				[nicvf_hw_stats[stat].index];
336964cb69bSSunil Goutham 	for (stat = 0; stat < nicvf_n_drv_stats; stat++) {
337964cb69bSSunil Goutham 		tmp_stats = 0;
338964cb69bSSunil Goutham 		for_each_possible_cpu(cpu)
339964cb69bSSunil Goutham 			tmp_stats += ((u64 *)per_cpu_ptr(nic->drv_stats, cpu))
3404863dea3SSunil Goutham 				     [nicvf_drv_stats[stat].index];
341964cb69bSSunil Goutham 		*(data++) = tmp_stats;
342964cb69bSSunil Goutham 	}
3434863dea3SSunil Goutham 
34492dc8769SSunil Goutham 	nicvf_get_qset_stats(nic, stats, &data);
3454863dea3SSunil Goutham 
34692dc8769SSunil Goutham 	for (sqs = 0; sqs < nic->sqs_count; sqs++) {
34792dc8769SSunil Goutham 		if (!nic->snicvf[sqs])
34892dc8769SSunil Goutham 			continue;
34992dc8769SSunil Goutham 		nicvf_get_qset_stats(nic->snicvf[sqs], stats, &data);
3504863dea3SSunil Goutham 	}
3514863dea3SSunil Goutham 
3524863dea3SSunil Goutham 	for (stat = 0; stat < BGX_RX_STATS_COUNT; stat++)
3534863dea3SSunil Goutham 		*(data++) = nic->bgx_stats.rx_stats[stat];
3544863dea3SSunil Goutham 	for (stat = 0; stat < BGX_TX_STATS_COUNT; stat++)
3554863dea3SSunil Goutham 		*(data++) = nic->bgx_stats.tx_stats[stat];
3564863dea3SSunil Goutham }
3574863dea3SSunil Goutham 
nicvf_get_regs_len(struct net_device * dev)3584863dea3SSunil Goutham static int nicvf_get_regs_len(struct net_device *dev)
3594863dea3SSunil Goutham {
3604863dea3SSunil Goutham 	return sizeof(u64) * NIC_VF_REG_COUNT;
3614863dea3SSunil Goutham }
3624863dea3SSunil Goutham 
nicvf_get_regs(struct net_device * dev,struct ethtool_regs * regs,void * reg)3634863dea3SSunil Goutham static void nicvf_get_regs(struct net_device *dev,
3644863dea3SSunil Goutham 			   struct ethtool_regs *regs, void *reg)
3654863dea3SSunil Goutham {
3664863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
3674863dea3SSunil Goutham 	u64 *p = (u64 *)reg;
3684863dea3SSunil Goutham 	u64 reg_offset;
3694863dea3SSunil Goutham 	int mbox, key, stat, q;
3704863dea3SSunil Goutham 	int i = 0;
3714863dea3SSunil Goutham 
3724863dea3SSunil Goutham 	regs->version = 0;
3734863dea3SSunil Goutham 	memset(p, 0, NIC_VF_REG_COUNT);
3744863dea3SSunil Goutham 
3754863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_VNIC_CFG);
3764863dea3SSunil Goutham 	/* Mailbox registers */
3774863dea3SSunil Goutham 	for (mbox = 0; mbox < NIC_PF_VF_MAILBOX_SIZE; mbox++)
3784863dea3SSunil Goutham 		p[i++] = nicvf_reg_read(nic,
3794863dea3SSunil Goutham 					NIC_VF_PF_MAILBOX_0_1 | (mbox << 3));
3804863dea3SSunil Goutham 
3814863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_VF_INT);
3824863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_VF_INT_W1S);
3834863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1C);
3844863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1S);
3854863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG);
3864863dea3SSunil Goutham 
3874863dea3SSunil Goutham 	for (key = 0; key < RSS_HASH_KEY_SIZE; key++)
3884863dea3SSunil Goutham 		p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_KEY_0_4 | (key << 3));
3894863dea3SSunil Goutham 
3904863dea3SSunil Goutham 	/* Tx/Rx statistics */
3914863dea3SSunil Goutham 	for (stat = 0; stat < TX_STATS_ENUM_LAST; stat++)
3924863dea3SSunil Goutham 		p[i++] = nicvf_reg_read(nic,
3934863dea3SSunil Goutham 					NIC_VNIC_TX_STAT_0_4 | (stat << 3));
3944863dea3SSunil Goutham 
3954863dea3SSunil Goutham 	for (i = 0; i < RX_STATS_ENUM_LAST; i++)
3964863dea3SSunil Goutham 		p[i++] = nicvf_reg_read(nic,
3974863dea3SSunil Goutham 					NIC_VNIC_RX_STAT_0_13 | (stat << 3));
3984863dea3SSunil Goutham 
3994863dea3SSunil Goutham 	p[i++] = nicvf_reg_read(nic, NIC_QSET_RQ_GEN_CFG);
4004863dea3SSunil Goutham 
4014863dea3SSunil Goutham 	/* All completion queue's registers */
4024863dea3SSunil Goutham 	for (q = 0; q < MAX_CMP_QUEUES_PER_QS; q++) {
4034863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG, q);
4044863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG2, q);
4054863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_THRESH, q);
4064863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_BASE, q);
4074863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, q);
4084863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_TAIL, q);
4094863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DOOR, q);
4104863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, q);
4114863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS2, q);
4124863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DEBUG, q);
4134863dea3SSunil Goutham 	}
4144863dea3SSunil Goutham 
4154863dea3SSunil Goutham 	/* All receive queue's registers */
4164863dea3SSunil Goutham 	for (q = 0; q < MAX_RCV_QUEUES_PER_QS; q++) {
4174863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RQ_0_7_CFG, q);
4184863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic,
4194863dea3SSunil Goutham 						  NIC_QSET_RQ_0_7_STAT_0_1, q);
4204863dea3SSunil Goutham 		reg_offset = NIC_QSET_RQ_0_7_STAT_0_1 | (1 << 3);
4214863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
4224863dea3SSunil Goutham 	}
4234863dea3SSunil Goutham 
4244863dea3SSunil Goutham 	for (q = 0; q < MAX_SND_QUEUES_PER_QS; q++) {
4254863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, q);
4264863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_THRESH, q);
4274863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_BASE, q);
4284863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, q);
4294863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_TAIL, q);
4304863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DOOR, q);
4314863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STATUS, q);
4324863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DEBUG, q);
4331423661fSDavid Daney 		/* Padding, was NIC_QSET_SQ_0_7_CNM_CHG, which
4341423661fSDavid Daney 		 * produces bus errors when read
4351423661fSDavid Daney 		 */
4361423661fSDavid Daney 		p[i++] = 0;
4374863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1, q);
4384863dea3SSunil Goutham 		reg_offset = NIC_QSET_SQ_0_7_STAT_0_1 | (1 << 3);
4394863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
4404863dea3SSunil Goutham 	}
4414863dea3SSunil Goutham 
4424863dea3SSunil Goutham 	for (q = 0; q < MAX_RCV_BUF_DESC_RINGS_PER_QS; q++) {
4434863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_CFG, q);
4444863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_THRESH, q);
4454863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_BASE, q);
4464863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, q);
4474863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, q);
4484863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_DOOR, q);
4494863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic,
4504863dea3SSunil Goutham 					      NIC_QSET_RBDR_0_1_STATUS0, q);
4514863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic,
4524863dea3SSunil Goutham 					      NIC_QSET_RBDR_0_1_STATUS1, q);
4534863dea3SSunil Goutham 		reg_offset = NIC_QSET_RBDR_0_1_PREFETCH_STATUS;
4544863dea3SSunil Goutham 		p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
4554863dea3SSunil Goutham 	}
4564863dea3SSunil Goutham }
4574863dea3SSunil Goutham 
nicvf_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * cmd,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)4584863dea3SSunil Goutham static int nicvf_get_coalesce(struct net_device *netdev,
459f3ccfda1SYufeng Mo 			      struct ethtool_coalesce *cmd,
460f3ccfda1SYufeng Mo 			      struct kernel_ethtool_coalesce *kernel_coal,
461f3ccfda1SYufeng Mo 			      struct netlink_ext_ack *extack)
4624863dea3SSunil Goutham {
4634863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
4644863dea3SSunil Goutham 
4654863dea3SSunil Goutham 	cmd->rx_coalesce_usecs = nic->cq_coalesce_usecs;
4664863dea3SSunil Goutham 	return 0;
4674863dea3SSunil Goutham }
4684863dea3SSunil Goutham 
nicvf_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)4694863dea3SSunil Goutham static void nicvf_get_ringparam(struct net_device *netdev,
47074624944SHao Chen 				struct ethtool_ringparam *ring,
47174624944SHao Chen 				struct kernel_ethtool_ringparam *kernel_ring,
47274624944SHao Chen 				struct netlink_ext_ack *extack)
4734863dea3SSunil Goutham {
4744863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
4754863dea3SSunil Goutham 	struct queue_set *qs = nic->qs;
4764863dea3SSunil Goutham 
477fff4ffddSSunil Goutham 	ring->rx_max_pending = MAX_CMP_QUEUE_LEN;
478fff4ffddSSunil Goutham 	ring->rx_pending = qs->cq_len;
4794863dea3SSunil Goutham 	ring->tx_max_pending = MAX_SND_QUEUE_LEN;
4804863dea3SSunil Goutham 	ring->tx_pending = qs->sq_len;
4814863dea3SSunil Goutham }
4824863dea3SSunil Goutham 
nicvf_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)483fff4ffddSSunil Goutham static int nicvf_set_ringparam(struct net_device *netdev,
48474624944SHao Chen 			       struct ethtool_ringparam *ring,
48574624944SHao Chen 			       struct kernel_ethtool_ringparam *kernel_ring,
48674624944SHao Chen 			       struct netlink_ext_ack *extack)
487fff4ffddSSunil Goutham {
488fff4ffddSSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
489fff4ffddSSunil Goutham 	struct queue_set *qs = nic->qs;
490fff4ffddSSunil Goutham 	u32 rx_count, tx_count;
491fff4ffddSSunil Goutham 
492fff4ffddSSunil Goutham 	/* Due to HW errata this is not supported on T88 pass 1.x silicon */
493fff4ffddSSunil Goutham 	if (pass1_silicon(nic->pdev))
494fff4ffddSSunil Goutham 		return -EINVAL;
495fff4ffddSSunil Goutham 
496fff4ffddSSunil Goutham 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
497fff4ffddSSunil Goutham 		return -EINVAL;
498fff4ffddSSunil Goutham 
499fff4ffddSSunil Goutham 	tx_count = clamp_t(u32, ring->tx_pending,
500fff4ffddSSunil Goutham 			   MIN_SND_QUEUE_LEN, MAX_SND_QUEUE_LEN);
501fff4ffddSSunil Goutham 	rx_count = clamp_t(u32, ring->rx_pending,
502fff4ffddSSunil Goutham 			   MIN_CMP_QUEUE_LEN, MAX_CMP_QUEUE_LEN);
503fff4ffddSSunil Goutham 
504fff4ffddSSunil Goutham 	if ((tx_count == qs->sq_len) && (rx_count == qs->cq_len))
505fff4ffddSSunil Goutham 		return 0;
506fff4ffddSSunil Goutham 
507fff4ffddSSunil Goutham 	/* Permitted lengths are 1K, 2K, 4K, 8K, 16K, 32K, 64K */
508fff4ffddSSunil Goutham 	qs->sq_len = rounddown_pow_of_two(tx_count);
509fff4ffddSSunil Goutham 	qs->cq_len = rounddown_pow_of_two(rx_count);
510fff4ffddSSunil Goutham 
511fff4ffddSSunil Goutham 	if (netif_running(netdev)) {
512fff4ffddSSunil Goutham 		nicvf_stop(netdev);
513fff4ffddSSunil Goutham 		nicvf_open(netdev);
514fff4ffddSSunil Goutham 	}
515fff4ffddSSunil Goutham 
516fff4ffddSSunil Goutham 	return 0;
517fff4ffddSSunil Goutham }
518fff4ffddSSunil Goutham 
nicvf_get_rss_hash_opts(struct nicvf * nic,struct ethtool_rxnfc * info)5194863dea3SSunil Goutham static int nicvf_get_rss_hash_opts(struct nicvf *nic,
5204863dea3SSunil Goutham 				   struct ethtool_rxnfc *info)
5214863dea3SSunil Goutham {
5224863dea3SSunil Goutham 	info->data = 0;
5234863dea3SSunil Goutham 
5244863dea3SSunil Goutham 	switch (info->flow_type) {
5254863dea3SSunil Goutham 	case TCP_V4_FLOW:
5264863dea3SSunil Goutham 	case TCP_V6_FLOW:
5274863dea3SSunil Goutham 	case UDP_V4_FLOW:
5284863dea3SSunil Goutham 	case UDP_V6_FLOW:
5294863dea3SSunil Goutham 	case SCTP_V4_FLOW:
5304863dea3SSunil Goutham 	case SCTP_V6_FLOW:
5314863dea3SSunil Goutham 		info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
532df561f66SGustavo A. R. Silva 		fallthrough;
5334863dea3SSunil Goutham 	case IPV4_FLOW:
5344863dea3SSunil Goutham 	case IPV6_FLOW:
5354863dea3SSunil Goutham 		info->data |= RXH_IP_SRC | RXH_IP_DST;
5364863dea3SSunil Goutham 		break;
5374863dea3SSunil Goutham 	default:
5384863dea3SSunil Goutham 		return -EINVAL;
5394863dea3SSunil Goutham 	}
5404863dea3SSunil Goutham 
5414863dea3SSunil Goutham 	return 0;
5424863dea3SSunil Goutham }
5434863dea3SSunil Goutham 
nicvf_get_rxnfc(struct net_device * dev,struct ethtool_rxnfc * info,u32 * rules)5444863dea3SSunil Goutham static int nicvf_get_rxnfc(struct net_device *dev,
5454863dea3SSunil Goutham 			   struct ethtool_rxnfc *info, u32 *rules)
5464863dea3SSunil Goutham {
5474863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
5484863dea3SSunil Goutham 	int ret = -EOPNOTSUPP;
5494863dea3SSunil Goutham 
5504863dea3SSunil Goutham 	switch (info->cmd) {
5514863dea3SSunil Goutham 	case ETHTOOL_GRXRINGS:
55292dc8769SSunil Goutham 		info->data = nic->rx_queues;
5534863dea3SSunil Goutham 		ret = 0;
5544863dea3SSunil Goutham 		break;
5554863dea3SSunil Goutham 	case ETHTOOL_GRXFH:
5564863dea3SSunil Goutham 		return nicvf_get_rss_hash_opts(nic, info);
5574863dea3SSunil Goutham 	default:
5584863dea3SSunil Goutham 		break;
5594863dea3SSunil Goutham 	}
5604863dea3SSunil Goutham 	return ret;
5614863dea3SSunil Goutham }
5624863dea3SSunil Goutham 
nicvf_set_rss_hash_opts(struct nicvf * nic,struct ethtool_rxnfc * info)5634863dea3SSunil Goutham static int nicvf_set_rss_hash_opts(struct nicvf *nic,
5644863dea3SSunil Goutham 				   struct ethtool_rxnfc *info)
5654863dea3SSunil Goutham {
5664863dea3SSunil Goutham 	struct nicvf_rss_info *rss = &nic->rss_info;
5674863dea3SSunil Goutham 	u64 rss_cfg = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG);
5684863dea3SSunil Goutham 
5694863dea3SSunil Goutham 	if (!rss->enable)
5704863dea3SSunil Goutham 		netdev_err(nic->netdev,
5714863dea3SSunil Goutham 			   "RSS is disabled, hash cannot be set\n");
5724863dea3SSunil Goutham 
5734863dea3SSunil Goutham 	netdev_info(nic->netdev, "Set RSS flow type = %d, data = %lld\n",
5744863dea3SSunil Goutham 		    info->flow_type, info->data);
5754863dea3SSunil Goutham 
5764863dea3SSunil Goutham 	if (!(info->data & RXH_IP_SRC) || !(info->data & RXH_IP_DST))
5774863dea3SSunil Goutham 		return -EINVAL;
5784863dea3SSunil Goutham 
5794863dea3SSunil Goutham 	switch (info->flow_type) {
5804863dea3SSunil Goutham 	case TCP_V4_FLOW:
5814863dea3SSunil Goutham 	case TCP_V6_FLOW:
5824863dea3SSunil Goutham 		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
5834863dea3SSunil Goutham 		case 0:
5844863dea3SSunil Goutham 			rss_cfg &= ~(1ULL << RSS_HASH_TCP);
5854863dea3SSunil Goutham 			break;
5864863dea3SSunil Goutham 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
5874863dea3SSunil Goutham 			rss_cfg |= (1ULL << RSS_HASH_TCP);
5884863dea3SSunil Goutham 			break;
5894863dea3SSunil Goutham 		default:
5904863dea3SSunil Goutham 			return -EINVAL;
5914863dea3SSunil Goutham 		}
5924863dea3SSunil Goutham 		break;
5934863dea3SSunil Goutham 	case UDP_V4_FLOW:
5944863dea3SSunil Goutham 	case UDP_V6_FLOW:
5954863dea3SSunil Goutham 		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
5964863dea3SSunil Goutham 		case 0:
5974863dea3SSunil Goutham 			rss_cfg &= ~(1ULL << RSS_HASH_UDP);
5984863dea3SSunil Goutham 			break;
5994863dea3SSunil Goutham 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
6004863dea3SSunil Goutham 			rss_cfg |= (1ULL << RSS_HASH_UDP);
6014863dea3SSunil Goutham 			break;
6024863dea3SSunil Goutham 		default:
6034863dea3SSunil Goutham 			return -EINVAL;
6044863dea3SSunil Goutham 		}
6054863dea3SSunil Goutham 		break;
6064863dea3SSunil Goutham 	case SCTP_V4_FLOW:
6074863dea3SSunil Goutham 	case SCTP_V6_FLOW:
6084863dea3SSunil Goutham 		switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
6094863dea3SSunil Goutham 		case 0:
6104863dea3SSunil Goutham 			rss_cfg &= ~(1ULL << RSS_HASH_L4ETC);
6114863dea3SSunil Goutham 			break;
6124863dea3SSunil Goutham 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
6134863dea3SSunil Goutham 			rss_cfg |= (1ULL << RSS_HASH_L4ETC);
6144863dea3SSunil Goutham 			break;
6154863dea3SSunil Goutham 		default:
6164863dea3SSunil Goutham 			return -EINVAL;
6174863dea3SSunil Goutham 		}
6184863dea3SSunil Goutham 		break;
6194863dea3SSunil Goutham 	case IPV4_FLOW:
6204863dea3SSunil Goutham 	case IPV6_FLOW:
6214863dea3SSunil Goutham 		rss_cfg = RSS_HASH_IP;
6224863dea3SSunil Goutham 		break;
6234863dea3SSunil Goutham 	default:
6244863dea3SSunil Goutham 		return -EINVAL;
6254863dea3SSunil Goutham 	}
6264863dea3SSunil Goutham 
6274863dea3SSunil Goutham 	nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss_cfg);
6284863dea3SSunil Goutham 	return 0;
6294863dea3SSunil Goutham }
6304863dea3SSunil Goutham 
nicvf_set_rxnfc(struct net_device * dev,struct ethtool_rxnfc * info)6314863dea3SSunil Goutham static int nicvf_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
6324863dea3SSunil Goutham {
6334863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
6344863dea3SSunil Goutham 
6354863dea3SSunil Goutham 	switch (info->cmd) {
6364863dea3SSunil Goutham 	case ETHTOOL_SRXFH:
6374863dea3SSunil Goutham 		return nicvf_set_rss_hash_opts(nic, info);
6384863dea3SSunil Goutham 	default:
6394863dea3SSunil Goutham 		break;
6404863dea3SSunil Goutham 	}
6414863dea3SSunil Goutham 	return -EOPNOTSUPP;
6424863dea3SSunil Goutham }
6434863dea3SSunil Goutham 
nicvf_get_rxfh_key_size(struct net_device * netdev)6444863dea3SSunil Goutham static u32 nicvf_get_rxfh_key_size(struct net_device *netdev)
6454863dea3SSunil Goutham {
6464863dea3SSunil Goutham 	return RSS_HASH_KEY_SIZE * sizeof(u64);
6474863dea3SSunil Goutham }
6484863dea3SSunil Goutham 
nicvf_get_rxfh_indir_size(struct net_device * dev)6494863dea3SSunil Goutham static u32 nicvf_get_rxfh_indir_size(struct net_device *dev)
6504863dea3SSunil Goutham {
6514863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
6524863dea3SSunil Goutham 
6534863dea3SSunil Goutham 	return nic->rss_info.rss_size;
6544863dea3SSunil Goutham }
6554863dea3SSunil Goutham 
nicvf_get_rxfh(struct net_device * dev,u32 * indir,u8 * hkey,u8 * hfunc)6564863dea3SSunil Goutham static int nicvf_get_rxfh(struct net_device *dev, u32 *indir, u8 *hkey,
6574863dea3SSunil Goutham 			  u8 *hfunc)
6584863dea3SSunil Goutham {
6594863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
6604863dea3SSunil Goutham 	struct nicvf_rss_info *rss = &nic->rss_info;
6614863dea3SSunil Goutham 	int idx;
6624863dea3SSunil Goutham 
6634863dea3SSunil Goutham 	if (indir) {
6644863dea3SSunil Goutham 		for (idx = 0; idx < rss->rss_size; idx++)
6654863dea3SSunil Goutham 			indir[idx] = rss->ind_tbl[idx];
6664863dea3SSunil Goutham 	}
6674863dea3SSunil Goutham 
6684863dea3SSunil Goutham 	if (hkey)
6694863dea3SSunil Goutham 		memcpy(hkey, rss->key, RSS_HASH_KEY_SIZE * sizeof(u64));
6704863dea3SSunil Goutham 
6714863dea3SSunil Goutham 	if (hfunc)
6724863dea3SSunil Goutham 		*hfunc = ETH_RSS_HASH_TOP;
6734863dea3SSunil Goutham 
6744863dea3SSunil Goutham 	return 0;
6754863dea3SSunil Goutham }
6764863dea3SSunil Goutham 
nicvf_set_rxfh(struct net_device * dev,const u32 * indir,const u8 * hkey,const u8 hfunc)6774863dea3SSunil Goutham static int nicvf_set_rxfh(struct net_device *dev, const u32 *indir,
678171d87acSRobert Richter 			  const u8 *hkey, const u8 hfunc)
6794863dea3SSunil Goutham {
6804863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
6814863dea3SSunil Goutham 	struct nicvf_rss_info *rss = &nic->rss_info;
6824863dea3SSunil Goutham 	int idx;
6834863dea3SSunil Goutham 
68489987844SAleksey Makarov 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
6854863dea3SSunil Goutham 		return -EOPNOTSUPP;
6864863dea3SSunil Goutham 
68738bb5d4fSSunil Goutham 	if (!rss->enable) {
68838bb5d4fSSunil Goutham 		netdev_err(nic->netdev,
68938bb5d4fSSunil Goutham 			   "RSS is disabled, cannot change settings\n");
69038bb5d4fSSunil Goutham 		return -EIO;
69138bb5d4fSSunil Goutham 	}
69238bb5d4fSSunil Goutham 
6934863dea3SSunil Goutham 	if (indir) {
6944863dea3SSunil Goutham 		for (idx = 0; idx < rss->rss_size; idx++)
6954863dea3SSunil Goutham 			rss->ind_tbl[idx] = indir[idx];
6964863dea3SSunil Goutham 	}
6974863dea3SSunil Goutham 
6984863dea3SSunil Goutham 	if (hkey) {
6994863dea3SSunil Goutham 		memcpy(rss->key, hkey, RSS_HASH_KEY_SIZE * sizeof(u64));
7004863dea3SSunil Goutham 		nicvf_set_rss_key(nic);
7014863dea3SSunil Goutham 	}
7024863dea3SSunil Goutham 
7034863dea3SSunil Goutham 	nicvf_config_rss(nic);
7044863dea3SSunil Goutham 	return 0;
7054863dea3SSunil Goutham }
7064863dea3SSunil Goutham 
7074863dea3SSunil Goutham /* Get no of queues device supports and current queue count */
nicvf_get_channels(struct net_device * dev,struct ethtool_channels * channel)7084863dea3SSunil Goutham static void nicvf_get_channels(struct net_device *dev,
7094863dea3SSunil Goutham 			       struct ethtool_channels *channel)
7104863dea3SSunil Goutham {
7114863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
7124863dea3SSunil Goutham 
7134863dea3SSunil Goutham 	memset(channel, 0, sizeof(*channel));
7144863dea3SSunil Goutham 
71592dc8769SSunil Goutham 	channel->max_rx = nic->max_queues;
71692dc8769SSunil Goutham 	channel->max_tx = nic->max_queues;
7174863dea3SSunil Goutham 
71892dc8769SSunil Goutham 	channel->rx_count = nic->rx_queues;
71992dc8769SSunil Goutham 	channel->tx_count = nic->tx_queues;
7204863dea3SSunil Goutham }
7214863dea3SSunil Goutham 
7224863dea3SSunil Goutham /* Set no of Tx, Rx queues to be used */
nicvf_set_channels(struct net_device * dev,struct ethtool_channels * channel)7234863dea3SSunil Goutham static int nicvf_set_channels(struct net_device *dev,
7244863dea3SSunil Goutham 			      struct ethtool_channels *channel)
7254863dea3SSunil Goutham {
7264863dea3SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
7274863dea3SSunil Goutham 	int err = 0;
728c62cd3c4SSunil Goutham 	bool if_up = netif_running(dev);
72905c773f5SSunil Goutham 	u8 cqcount, txq_count;
7304863dea3SSunil Goutham 
7314863dea3SSunil Goutham 	if (!channel->rx_count || !channel->tx_count)
7324863dea3SSunil Goutham 		return -EINVAL;
73392dc8769SSunil Goutham 	if (channel->rx_count > nic->max_queues)
7344863dea3SSunil Goutham 		return -EINVAL;
73592dc8769SSunil Goutham 	if (channel->tx_count > nic->max_queues)
7364863dea3SSunil Goutham 		return -EINVAL;
7374863dea3SSunil Goutham 
738*3c249fe4SLorenzo Bianconi 	if (channel->tx_count + channel->rx_count > nic->max_queues) {
739*3c249fe4SLorenzo Bianconi 		if (nic->xdp_prog) {
74005c773f5SSunil Goutham 			netdev_err(nic->netdev,
74105c773f5SSunil Goutham 				   "XDP mode, RXQs + TXQs > Max %d\n",
74205c773f5SSunil Goutham 				   nic->max_queues);
74305c773f5SSunil Goutham 			return -EINVAL;
74405c773f5SSunil Goutham 		}
74505c773f5SSunil Goutham 
746*3c249fe4SLorenzo Bianconi 		xdp_clear_features_flag(nic->netdev);
747*3c249fe4SLorenzo Bianconi 	} else if (!pass1_silicon(nic->pdev)) {
748*3c249fe4SLorenzo Bianconi 		xdp_set_features_flag(dev, NETDEV_XDP_ACT_BASIC);
749*3c249fe4SLorenzo Bianconi 	}
750*3c249fe4SLorenzo Bianconi 
751c62cd3c4SSunil Goutham 	if (if_up)
752c62cd3c4SSunil Goutham 		nicvf_stop(dev);
753c62cd3c4SSunil Goutham 
75405c773f5SSunil Goutham 	nic->rx_queues = channel->rx_count;
75505c773f5SSunil Goutham 	nic->tx_queues = channel->tx_count;
75605c773f5SSunil Goutham 	if (!nic->xdp_prog)
75705c773f5SSunil Goutham 		nic->xdp_tx_queues = 0;
75805c773f5SSunil Goutham 	else
75905c773f5SSunil Goutham 		nic->xdp_tx_queues = channel->rx_count;
76005c773f5SSunil Goutham 
76105c773f5SSunil Goutham 	txq_count = nic->xdp_tx_queues + nic->tx_queues;
76205c773f5SSunil Goutham 	cqcount = max(nic->rx_queues, txq_count);
76392dc8769SSunil Goutham 
76492dc8769SSunil Goutham 	if (cqcount > MAX_CMP_QUEUES_PER_QS) {
76592dc8769SSunil Goutham 		nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS);
76692dc8769SSunil Goutham 		nic->sqs_count = (nic->sqs_count / MAX_CMP_QUEUES_PER_QS) - 1;
76792dc8769SSunil Goutham 	} else {
76892dc8769SSunil Goutham 		nic->sqs_count = 0;
76992dc8769SSunil Goutham 	}
77092dc8769SSunil Goutham 
77105c773f5SSunil Goutham 	nic->qs->rq_cnt = min_t(u8, nic->rx_queues, MAX_RCV_QUEUES_PER_QS);
77205c773f5SSunil Goutham 	nic->qs->sq_cnt = min_t(u8, txq_count, MAX_SND_QUEUES_PER_QS);
7734863dea3SSunil Goutham 	nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
7744863dea3SSunil Goutham 
77592dc8769SSunil Goutham 	err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues);
7764863dea3SSunil Goutham 	if (err)
7774863dea3SSunil Goutham 		return err;
7784863dea3SSunil Goutham 
779c62cd3c4SSunil Goutham 	if (if_up)
7804863dea3SSunil Goutham 		nicvf_open(dev);
781c62cd3c4SSunil Goutham 
7824863dea3SSunil Goutham 	netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
78392dc8769SSunil Goutham 		    nic->tx_queues, nic->rx_queues);
7844863dea3SSunil Goutham 
7854863dea3SSunil Goutham 	return err;
7864863dea3SSunil Goutham }
7874863dea3SSunil Goutham 
nicvf_get_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)788430da208SSunil Goutham static void nicvf_get_pauseparam(struct net_device *dev,
789430da208SSunil Goutham 				 struct ethtool_pauseparam *pause)
790430da208SSunil Goutham {
791430da208SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
792430da208SSunil Goutham 	union nic_mbx mbx = {};
793430da208SSunil Goutham 
794430da208SSunil Goutham 	/* Supported only for 10G/40G interfaces */
795430da208SSunil Goutham 	if ((nic->mac_type == BGX_MODE_SGMII) ||
796430da208SSunil Goutham 	    (nic->mac_type == BGX_MODE_QSGMII) ||
797430da208SSunil Goutham 	    (nic->mac_type == BGX_MODE_RGMII))
798430da208SSunil Goutham 		return;
799430da208SSunil Goutham 
800430da208SSunil Goutham 	mbx.pfc.msg = NIC_MBOX_MSG_PFC;
801430da208SSunil Goutham 	mbx.pfc.get = 1;
802430da208SSunil Goutham 	if (!nicvf_send_msg_to_pf(nic, &mbx)) {
803430da208SSunil Goutham 		pause->autoneg = nic->pfc.autoneg;
804430da208SSunil Goutham 		pause->rx_pause = nic->pfc.fc_rx;
805430da208SSunil Goutham 		pause->tx_pause = nic->pfc.fc_tx;
806430da208SSunil Goutham 	}
807430da208SSunil Goutham }
808430da208SSunil Goutham 
nicvf_set_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)809430da208SSunil Goutham static int nicvf_set_pauseparam(struct net_device *dev,
810430da208SSunil Goutham 				struct ethtool_pauseparam *pause)
811430da208SSunil Goutham {
812430da208SSunil Goutham 	struct nicvf *nic = netdev_priv(dev);
813430da208SSunil Goutham 	union nic_mbx mbx = {};
814430da208SSunil Goutham 
815430da208SSunil Goutham 	/* Supported only for 10G/40G interfaces */
816430da208SSunil Goutham 	if ((nic->mac_type == BGX_MODE_SGMII) ||
817430da208SSunil Goutham 	    (nic->mac_type == BGX_MODE_QSGMII) ||
818430da208SSunil Goutham 	    (nic->mac_type == BGX_MODE_RGMII))
819430da208SSunil Goutham 		return -EOPNOTSUPP;
820430da208SSunil Goutham 
821430da208SSunil Goutham 	if (pause->autoneg)
822430da208SSunil Goutham 		return -EOPNOTSUPP;
823430da208SSunil Goutham 
824430da208SSunil Goutham 	mbx.pfc.msg = NIC_MBOX_MSG_PFC;
825430da208SSunil Goutham 	mbx.pfc.get = 0;
826430da208SSunil Goutham 	mbx.pfc.fc_rx = pause->rx_pause;
827430da208SSunil Goutham 	mbx.pfc.fc_tx = pause->tx_pause;
828430da208SSunil Goutham 	if (nicvf_send_msg_to_pf(nic, &mbx))
829430da208SSunil Goutham 		return -EAGAIN;
830430da208SSunil Goutham 
831430da208SSunil Goutham 	nic->pfc.fc_rx = pause->rx_pause;
832430da208SSunil Goutham 	nic->pfc.fc_tx = pause->tx_pause;
833430da208SSunil Goutham 
834430da208SSunil Goutham 	return 0;
835430da208SSunil Goutham }
836430da208SSunil Goutham 
nicvf_get_ts_info(struct net_device * netdev,struct ethtool_ts_info * info)8374a875509SSunil Goutham static int nicvf_get_ts_info(struct net_device *netdev,
8384a875509SSunil Goutham 			     struct ethtool_ts_info *info)
8394a875509SSunil Goutham {
8404a875509SSunil Goutham 	struct nicvf *nic = netdev_priv(netdev);
8414a875509SSunil Goutham 
8424a875509SSunil Goutham 	if (!nic->ptp_clock)
8434a875509SSunil Goutham 		return ethtool_op_get_ts_info(netdev, info);
8444a875509SSunil Goutham 
8454a875509SSunil Goutham 	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
8464a875509SSunil Goutham 				SOF_TIMESTAMPING_RX_SOFTWARE |
8474a875509SSunil Goutham 				SOF_TIMESTAMPING_SOFTWARE |
8484a875509SSunil Goutham 				SOF_TIMESTAMPING_TX_HARDWARE |
8494a875509SSunil Goutham 				SOF_TIMESTAMPING_RX_HARDWARE |
8504a875509SSunil Goutham 				SOF_TIMESTAMPING_RAW_HARDWARE;
8514a875509SSunil Goutham 
8524a875509SSunil Goutham 	info->phc_index = cavium_ptp_clock_index(nic->ptp_clock);
8534a875509SSunil Goutham 
8544a875509SSunil Goutham 	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
8554a875509SSunil Goutham 
8564a875509SSunil Goutham 	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
8574a875509SSunil Goutham 			   (1 << HWTSTAMP_FILTER_ALL);
8584a875509SSunil Goutham 
8594a875509SSunil Goutham 	return 0;
8604a875509SSunil Goutham }
8614a875509SSunil Goutham 
8624863dea3SSunil Goutham static const struct ethtool_ops nicvf_ethtool_ops = {
8630b72a9a1SSunil Goutham 	.get_link		= nicvf_get_link,
8644863dea3SSunil Goutham 	.get_drvinfo		= nicvf_get_drvinfo,
8654863dea3SSunil Goutham 	.get_msglevel		= nicvf_get_msglevel,
8664863dea3SSunil Goutham 	.set_msglevel		= nicvf_set_msglevel,
8674863dea3SSunil Goutham 	.get_strings		= nicvf_get_strings,
8684863dea3SSunil Goutham 	.get_sset_count		= nicvf_get_sset_count,
8694863dea3SSunil Goutham 	.get_ethtool_stats	= nicvf_get_ethtool_stats,
8704863dea3SSunil Goutham 	.get_regs_len		= nicvf_get_regs_len,
8714863dea3SSunil Goutham 	.get_regs		= nicvf_get_regs,
8724863dea3SSunil Goutham 	.get_coalesce		= nicvf_get_coalesce,
8734863dea3SSunil Goutham 	.get_ringparam		= nicvf_get_ringparam,
874fff4ffddSSunil Goutham 	.set_ringparam		= nicvf_set_ringparam,
8754863dea3SSunil Goutham 	.get_rxnfc		= nicvf_get_rxnfc,
8764863dea3SSunil Goutham 	.set_rxnfc		= nicvf_set_rxnfc,
8774863dea3SSunil Goutham 	.get_rxfh_key_size	= nicvf_get_rxfh_key_size,
8784863dea3SSunil Goutham 	.get_rxfh_indir_size	= nicvf_get_rxfh_indir_size,
8794863dea3SSunil Goutham 	.get_rxfh		= nicvf_get_rxfh,
8804863dea3SSunil Goutham 	.set_rxfh		= nicvf_set_rxfh,
8814863dea3SSunil Goutham 	.get_channels		= nicvf_get_channels,
8824863dea3SSunil Goutham 	.set_channels		= nicvf_set_channels,
883430da208SSunil Goutham 	.get_pauseparam         = nicvf_get_pauseparam,
884430da208SSunil Goutham 	.set_pauseparam         = nicvf_set_pauseparam,
8854a875509SSunil Goutham 	.get_ts_info		= nicvf_get_ts_info,
886bfd8d977SPhilippe Reynes 	.get_link_ksettings	= nicvf_get_link_ksettings,
8874863dea3SSunil Goutham };
8884863dea3SSunil Goutham 
nicvf_set_ethtool_ops(struct net_device * netdev)8894863dea3SSunil Goutham void nicvf_set_ethtool_ops(struct net_device *netdev)
8904863dea3SSunil Goutham {
8914863dea3SSunil Goutham 	netdev->ethtool_ops = &nicvf_ethtool_ops;
8924863dea3SSunil Goutham }
893