xref: /openbmc/linux/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
1d45d8979SChristina Jacob // SPDX-License-Identifier: GPL-2.0
2cb0e3ec4SSunil Goutham /* Marvell RVU Ethernet driver
3d45d8979SChristina Jacob  *
4cb0e3ec4SSunil Goutham  * Copyright (C) 2020 Marvell.
5d45d8979SChristina Jacob  *
6d45d8979SChristina Jacob  */
7d45d8979SChristina Jacob 
8d45d8979SChristina Jacob #include <linux/pci.h>
9d45d8979SChristina Jacob #include <linux/ethtool.h>
10d45d8979SChristina Jacob #include <linux/stddef.h>
11d45d8979SChristina Jacob #include <linux/etherdevice.h>
12d45d8979SChristina Jacob #include <linux/log2.h>
13c9c12d33SAleksey Makarov #include <linux/net_tstamp.h>
141a50280cSChristina Jacob #include <linux/linkmode.h>
15d45d8979SChristina Jacob 
16d45d8979SChristina Jacob #include "otx2_common.h"
17c9c12d33SAleksey Makarov #include "otx2_ptp.h"
18d45d8979SChristina Jacob 
19ef6c8da7SGeetha sowjanya #define DRV_NAME	"rvu-nicpf"
20ef6c8da7SGeetha sowjanya #define DRV_VF_NAME	"rvu-nicvf"
21d45d8979SChristina Jacob 
22d45d8979SChristina Jacob struct otx2_stat {
23d45d8979SChristina Jacob 	char name[ETH_GSTRING_LEN];
24d45d8979SChristina Jacob 	unsigned int index;
25d45d8979SChristina Jacob };
26d45d8979SChristina Jacob 
27d45d8979SChristina Jacob /* HW device stats */
28d45d8979SChristina Jacob #define OTX2_DEV_STAT(stat) { \
29d45d8979SChristina Jacob 	.name = #stat, \
30d45d8979SChristina Jacob 	.index = offsetof(struct otx2_dev_stats, stat) / sizeof(u64), \
31d45d8979SChristina Jacob }
32d45d8979SChristina Jacob 
331a50280cSChristina Jacob enum link_mode {
341a50280cSChristina Jacob 	OTX2_MODE_SUPPORTED,
351a50280cSChristina Jacob 	OTX2_MODE_ADVERTISED
361a50280cSChristina Jacob };
371a50280cSChristina Jacob 
38d45d8979SChristina Jacob static const struct otx2_stat otx2_dev_stats[] = {
39d45d8979SChristina Jacob 	OTX2_DEV_STAT(rx_ucast_frames),
40d45d8979SChristina Jacob 	OTX2_DEV_STAT(rx_bcast_frames),
41d45d8979SChristina Jacob 	OTX2_DEV_STAT(rx_mcast_frames),
42d45d8979SChristina Jacob 
43d45d8979SChristina Jacob 	OTX2_DEV_STAT(tx_ucast_frames),
44d45d8979SChristina Jacob 	OTX2_DEV_STAT(tx_bcast_frames),
45d45d8979SChristina Jacob 	OTX2_DEV_STAT(tx_mcast_frames),
46d45d8979SChristina Jacob };
47d45d8979SChristina Jacob 
48d45d8979SChristina Jacob /* Driver level stats */
49d45d8979SChristina Jacob #define OTX2_DRV_STAT(stat) { \
50d45d8979SChristina Jacob 	.name = #stat, \
51d45d8979SChristina Jacob 	.index = offsetof(struct otx2_drv_stats, stat) / sizeof(atomic_t), \
52d45d8979SChristina Jacob }
53d45d8979SChristina Jacob 
54d45d8979SChristina Jacob static const struct otx2_stat otx2_drv_stats[] = {
55d45d8979SChristina Jacob 	OTX2_DRV_STAT(rx_fcs_errs),
56d45d8979SChristina Jacob 	OTX2_DRV_STAT(rx_oversize_errs),
57d45d8979SChristina Jacob 	OTX2_DRV_STAT(rx_undersize_errs),
58d45d8979SChristina Jacob 	OTX2_DRV_STAT(rx_csum_errs),
59d45d8979SChristina Jacob 	OTX2_DRV_STAT(rx_len_errs),
60d45d8979SChristina Jacob 	OTX2_DRV_STAT(rx_other_errs),
61d45d8979SChristina Jacob };
62d45d8979SChristina Jacob 
63d45d8979SChristina Jacob static const struct otx2_stat otx2_queue_stats[] = {
64d45d8979SChristina Jacob 	{ "bytes", 0 },
65d45d8979SChristina Jacob 	{ "frames", 1 },
66d45d8979SChristina Jacob };
67d45d8979SChristina Jacob 
68d45d8979SChristina Jacob static const unsigned int otx2_n_dev_stats = ARRAY_SIZE(otx2_dev_stats);
69d45d8979SChristina Jacob static const unsigned int otx2_n_drv_stats = ARRAY_SIZE(otx2_drv_stats);
70d45d8979SChristina Jacob static const unsigned int otx2_n_queue_stats = ARRAY_SIZE(otx2_queue_stats);
71d45d8979SChristina Jacob 
72d0cf9503SChristina Jacob static struct cgx_fw_data *otx2_get_fwdata(struct otx2_nic *pfvf);
73d0cf9503SChristina Jacob 
otx2_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)74d45d8979SChristina Jacob static void otx2_get_drvinfo(struct net_device *netdev,
75d45d8979SChristina Jacob 			     struct ethtool_drvinfo *info)
76d45d8979SChristina Jacob {
77d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
78d45d8979SChristina Jacob 
79f029c781SWolfram Sang 	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
80f029c781SWolfram Sang 	strscpy(info->bus_info, pci_name(pfvf->pdev), sizeof(info->bus_info));
81d45d8979SChristina Jacob }
82d45d8979SChristina Jacob 
otx2_get_qset_strings(struct otx2_nic * pfvf,u8 ** data,int qset)83d45d8979SChristina Jacob static void otx2_get_qset_strings(struct otx2_nic *pfvf, u8 **data, int qset)
84d45d8979SChristina Jacob {
85d45d8979SChristina Jacob 	int start_qidx = qset * pfvf->hw.rx_queues;
86d45d8979SChristina Jacob 	int qidx, stats;
87d45d8979SChristina Jacob 
88d45d8979SChristina Jacob 	for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) {
89d45d8979SChristina Jacob 		for (stats = 0; stats < otx2_n_queue_stats; stats++) {
90d45d8979SChristina Jacob 			sprintf(*data, "rxq%d: %s", qidx + start_qidx,
91d45d8979SChristina Jacob 				otx2_queue_stats[stats].name);
92d45d8979SChristina Jacob 			*data += ETH_GSTRING_LEN;
93d45d8979SChristina Jacob 		}
94d45d8979SChristina Jacob 	}
956cebb6a4SHariprasad Kelam 
966cebb6a4SHariprasad Kelam 	for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) {
97d45d8979SChristina Jacob 		for (stats = 0; stats < otx2_n_queue_stats; stats++) {
986cebb6a4SHariprasad Kelam 			if (qidx >= pfvf->hw.non_qos_queues)
996cebb6a4SHariprasad Kelam 				sprintf(*data, "txq_qos%d: %s",
1006cebb6a4SHariprasad Kelam 					qidx + start_qidx - pfvf->hw.non_qos_queues,
1016cebb6a4SHariprasad Kelam 					otx2_queue_stats[stats].name);
1026cebb6a4SHariprasad Kelam 			else
103d45d8979SChristina Jacob 				sprintf(*data, "txq%d: %s", qidx + start_qidx,
104d45d8979SChristina Jacob 					otx2_queue_stats[stats].name);
105d45d8979SChristina Jacob 			*data += ETH_GSTRING_LEN;
106d45d8979SChristina Jacob 		}
107d45d8979SChristina Jacob 	}
108d45d8979SChristina Jacob }
109d45d8979SChristina Jacob 
otx2_get_strings(struct net_device * netdev,u32 sset,u8 * data)110d45d8979SChristina Jacob static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
111d45d8979SChristina Jacob {
112d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
113d45d8979SChristina Jacob 	int stats;
114d45d8979SChristina Jacob 
115d45d8979SChristina Jacob 	if (sset != ETH_SS_STATS)
116d45d8979SChristina Jacob 		return;
117d45d8979SChristina Jacob 
118d45d8979SChristina Jacob 	for (stats = 0; stats < otx2_n_dev_stats; stats++) {
119d45d8979SChristina Jacob 		memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN);
120d45d8979SChristina Jacob 		data += ETH_GSTRING_LEN;
121d45d8979SChristina Jacob 	}
122d45d8979SChristina Jacob 
123d45d8979SChristina Jacob 	for (stats = 0; stats < otx2_n_drv_stats; stats++) {
124d45d8979SChristina Jacob 		memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN);
125d45d8979SChristina Jacob 		data += ETH_GSTRING_LEN;
126d45d8979SChristina Jacob 	}
127d45d8979SChristina Jacob 
128d45d8979SChristina Jacob 	otx2_get_qset_strings(pfvf, &data, 0);
129d45d8979SChristina Jacob 
13063f85c40SHariprasad Kelam 	if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) {
131d45d8979SChristina Jacob 		for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) {
132d45d8979SChristina Jacob 			sprintf(data, "cgx_rxstat%d: ", stats);
133d45d8979SChristina Jacob 			data += ETH_GSTRING_LEN;
134d45d8979SChristina Jacob 		}
135d45d8979SChristina Jacob 
136d45d8979SChristina Jacob 		for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) {
137d45d8979SChristina Jacob 			sprintf(data, "cgx_txstat%d: ", stats);
138d45d8979SChristina Jacob 			data += ETH_GSTRING_LEN;
139d45d8979SChristina Jacob 		}
14063f85c40SHariprasad Kelam 	}
141d45d8979SChristina Jacob 
142d45d8979SChristina Jacob 	strcpy(data, "reset_count");
143d45d8979SChristina Jacob 	data += ETH_GSTRING_LEN;
144d0cf9503SChristina Jacob 	sprintf(data, "Fec Corrected Errors: ");
145d0cf9503SChristina Jacob 	data += ETH_GSTRING_LEN;
146d0cf9503SChristina Jacob 	sprintf(data, "Fec Uncorrected Errors: ");
147d0cf9503SChristina Jacob 	data += ETH_GSTRING_LEN;
148d45d8979SChristina Jacob }
149d45d8979SChristina Jacob 
otx2_get_qset_stats(struct otx2_nic * pfvf,struct ethtool_stats * stats,u64 ** data)150d45d8979SChristina Jacob static void otx2_get_qset_stats(struct otx2_nic *pfvf,
151d45d8979SChristina Jacob 				struct ethtool_stats *stats, u64 **data)
152d45d8979SChristina Jacob {
153d45d8979SChristina Jacob 	int stat, qidx;
154d45d8979SChristina Jacob 
155d45d8979SChristina Jacob 	if (!pfvf)
156d45d8979SChristina Jacob 		return;
157d45d8979SChristina Jacob 	for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) {
158d45d8979SChristina Jacob 		if (!otx2_update_rq_stats(pfvf, qidx)) {
159d45d8979SChristina Jacob 			for (stat = 0; stat < otx2_n_queue_stats; stat++)
160d45d8979SChristina Jacob 				*((*data)++) = 0;
161d45d8979SChristina Jacob 			continue;
162d45d8979SChristina Jacob 		}
163d45d8979SChristina Jacob 		for (stat = 0; stat < otx2_n_queue_stats; stat++)
164d45d8979SChristina Jacob 			*((*data)++) = ((u64 *)&pfvf->qset.rq[qidx].stats)
165d45d8979SChristina Jacob 				[otx2_queue_stats[stat].index];
166d45d8979SChristina Jacob 	}
167d45d8979SChristina Jacob 
1686cebb6a4SHariprasad Kelam 	for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) {
169d45d8979SChristina Jacob 		if (!otx2_update_sq_stats(pfvf, qidx)) {
170d45d8979SChristina Jacob 			for (stat = 0; stat < otx2_n_queue_stats; stat++)
171d45d8979SChristina Jacob 				*((*data)++) = 0;
172d45d8979SChristina Jacob 			continue;
173d45d8979SChristina Jacob 		}
174d45d8979SChristina Jacob 		for (stat = 0; stat < otx2_n_queue_stats; stat++)
175d45d8979SChristina Jacob 			*((*data)++) = ((u64 *)&pfvf->qset.sq[qidx].stats)
176d45d8979SChristina Jacob 				[otx2_queue_stats[stat].index];
177d45d8979SChristina Jacob 	}
178d45d8979SChristina Jacob }
179d45d8979SChristina Jacob 
otx2_get_phy_fec_stats(struct otx2_nic * pfvf)180d0cf9503SChristina Jacob static int otx2_get_phy_fec_stats(struct otx2_nic *pfvf)
181d0cf9503SChristina Jacob {
182d0cf9503SChristina Jacob 	struct msg_req *req;
183d0cf9503SChristina Jacob 	int rc = -ENOMEM;
184d0cf9503SChristina Jacob 
185d0cf9503SChristina Jacob 	mutex_lock(&pfvf->mbox.lock);
186d0cf9503SChristina Jacob 	req = otx2_mbox_alloc_msg_cgx_get_phy_fec_stats(&pfvf->mbox);
187d0cf9503SChristina Jacob 	if (!req)
188d0cf9503SChristina Jacob 		goto end;
189d0cf9503SChristina Jacob 
190d0cf9503SChristina Jacob 	if (!otx2_sync_mbox_msg(&pfvf->mbox))
191d0cf9503SChristina Jacob 		rc = 0;
192d0cf9503SChristina Jacob end:
193d0cf9503SChristina Jacob 	mutex_unlock(&pfvf->mbox.lock);
194d0cf9503SChristina Jacob 	return rc;
195d0cf9503SChristina Jacob }
196d0cf9503SChristina Jacob 
197d45d8979SChristina Jacob /* Get device and per queue statistics */
otx2_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)198d45d8979SChristina Jacob static void otx2_get_ethtool_stats(struct net_device *netdev,
199d45d8979SChristina Jacob 				   struct ethtool_stats *stats, u64 *data)
200d45d8979SChristina Jacob {
201d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
202d0cf9503SChristina Jacob 	u64 fec_corr_blks, fec_uncorr_blks;
203d0cf9503SChristina Jacob 	struct cgx_fw_data *rsp;
204d45d8979SChristina Jacob 	int stat;
205d45d8979SChristina Jacob 
206d45d8979SChristina Jacob 	otx2_get_dev_stats(pfvf);
207d45d8979SChristina Jacob 	for (stat = 0; stat < otx2_n_dev_stats; stat++)
208d45d8979SChristina Jacob 		*(data++) = ((u64 *)&pfvf->hw.dev_stats)
209d45d8979SChristina Jacob 				[otx2_dev_stats[stat].index];
210d45d8979SChristina Jacob 
211d45d8979SChristina Jacob 	for (stat = 0; stat < otx2_n_drv_stats; stat++)
212d45d8979SChristina Jacob 		*(data++) = atomic_read(&((atomic_t *)&pfvf->hw.drv_stats)
213d45d8979SChristina Jacob 						[otx2_drv_stats[stat].index]);
214d45d8979SChristina Jacob 
215d45d8979SChristina Jacob 	otx2_get_qset_stats(pfvf, stats, &data);
21663f85c40SHariprasad Kelam 
21763f85c40SHariprasad Kelam 	if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) {
218d45d8979SChristina Jacob 		otx2_update_lmac_stats(pfvf);
219d45d8979SChristina Jacob 		for (stat = 0; stat < CGX_RX_STATS_COUNT; stat++)
220d45d8979SChristina Jacob 			*(data++) = pfvf->hw.cgx_rx_stats[stat];
221d45d8979SChristina Jacob 		for (stat = 0; stat < CGX_TX_STATS_COUNT; stat++)
222d45d8979SChristina Jacob 			*(data++) = pfvf->hw.cgx_tx_stats[stat];
22363f85c40SHariprasad Kelam 	}
22463f85c40SHariprasad Kelam 
225d45d8979SChristina Jacob 	*(data++) = pfvf->reset_count;
226d0cf9503SChristina Jacob 
227d0cf9503SChristina Jacob 	fec_corr_blks = pfvf->hw.cgx_fec_corr_blks;
228d0cf9503SChristina Jacob 	fec_uncorr_blks = pfvf->hw.cgx_fec_uncorr_blks;
229d0cf9503SChristina Jacob 
230d0cf9503SChristina Jacob 	rsp = otx2_get_fwdata(pfvf);
231d0cf9503SChristina Jacob 	if (!IS_ERR(rsp) && rsp->fwdata.phy.misc.has_fec_stats &&
232d0cf9503SChristina Jacob 	    !otx2_get_phy_fec_stats(pfvf)) {
233d0cf9503SChristina Jacob 		/* Fetch fwdata again because it's been recently populated with
234d0cf9503SChristina Jacob 		 * latest PHY FEC stats.
235d0cf9503SChristina Jacob 		 */
236d0cf9503SChristina Jacob 		rsp = otx2_get_fwdata(pfvf);
237d0cf9503SChristina Jacob 		if (!IS_ERR(rsp)) {
238d0cf9503SChristina Jacob 			struct fec_stats_s *p = &rsp->fwdata.phy.fec_stats;
239d0cf9503SChristina Jacob 
240d0cf9503SChristina Jacob 			if (pfvf->linfo.fec == OTX2_FEC_BASER) {
241d0cf9503SChristina Jacob 				fec_corr_blks   = p->brfec_corr_blks;
242d0cf9503SChristina Jacob 				fec_uncorr_blks = p->brfec_uncorr_blks;
243d0cf9503SChristina Jacob 			} else {
244d0cf9503SChristina Jacob 				fec_corr_blks   = p->rsfec_corr_cws;
245d0cf9503SChristina Jacob 				fec_uncorr_blks = p->rsfec_uncorr_cws;
246d0cf9503SChristina Jacob 			}
247d0cf9503SChristina Jacob 		}
248d0cf9503SChristina Jacob 	}
249d0cf9503SChristina Jacob 
250d0cf9503SChristina Jacob 	*(data++) = fec_corr_blks;
251d0cf9503SChristina Jacob 	*(data++) = fec_uncorr_blks;
252d45d8979SChristina Jacob }
253d45d8979SChristina Jacob 
otx2_get_sset_count(struct net_device * netdev,int sset)254d45d8979SChristina Jacob static int otx2_get_sset_count(struct net_device *netdev, int sset)
255d45d8979SChristina Jacob {
256d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
25763f85c40SHariprasad Kelam 	int qstats_count, mac_stats = 0;
258d45d8979SChristina Jacob 
259d45d8979SChristina Jacob 	if (sset != ETH_SS_STATS)
260d45d8979SChristina Jacob 		return -EINVAL;
261d45d8979SChristina Jacob 
262d45d8979SChristina Jacob 	qstats_count = otx2_n_queue_stats *
2636cebb6a4SHariprasad Kelam 		       (pfvf->hw.rx_queues + otx2_get_total_tx_queues(pfvf));
26463f85c40SHariprasad Kelam 	if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag))
26563f85c40SHariprasad Kelam 		mac_stats = CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT;
266d0cf9503SChristina Jacob 	otx2_update_lmac_fec_stats(pfvf);
267d45d8979SChristina Jacob 
268d45d8979SChristina Jacob 	return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count +
26963f85c40SHariprasad Kelam 	       mac_stats + OTX2_FEC_STATS_CNT + 1;
270d45d8979SChristina Jacob }
271d45d8979SChristina Jacob 
272d45d8979SChristina Jacob /* Get no of queues device supports and current queue count */
otx2_get_channels(struct net_device * dev,struct ethtool_channels * channel)273d45d8979SChristina Jacob static void otx2_get_channels(struct net_device *dev,
274d45d8979SChristina Jacob 			      struct ethtool_channels *channel)
275d45d8979SChristina Jacob {
276d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(dev);
277d45d8979SChristina Jacob 
278d45d8979SChristina Jacob 	channel->max_rx = pfvf->hw.max_queues;
279d45d8979SChristina Jacob 	channel->max_tx = pfvf->hw.max_queues;
280d45d8979SChristina Jacob 
281d45d8979SChristina Jacob 	channel->rx_count = pfvf->hw.rx_queues;
282d45d8979SChristina Jacob 	channel->tx_count = pfvf->hw.tx_queues;
283d45d8979SChristina Jacob }
284d45d8979SChristina Jacob 
285d45d8979SChristina Jacob /* Set no of Tx, Rx queues to be used */
otx2_set_channels(struct net_device * dev,struct ethtool_channels * channel)286d45d8979SChristina Jacob static int otx2_set_channels(struct net_device *dev,
287d45d8979SChristina Jacob 			     struct ethtool_channels *channel)
288d45d8979SChristina Jacob {
289d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(dev);
290d45d8979SChristina Jacob 	bool if_up = netif_running(dev);
2916cebb6a4SHariprasad Kelam 	int err, qos_txqs;
292d45d8979SChristina Jacob 
293d45d8979SChristina Jacob 	if (!channel->rx_count || !channel->tx_count)
294d45d8979SChristina Jacob 		return -EINVAL;
295d45d8979SChristina Jacob 
29668fbff68SSubbaraya Sundeep 	if (bitmap_weight(&pfvf->rq_bmap, pfvf->hw.rx_queues) > 1) {
29768fbff68SSubbaraya Sundeep 		netdev_err(dev,
29868fbff68SSubbaraya Sundeep 			   "Receive queues are in use by TC police action\n");
29968fbff68SSubbaraya Sundeep 		return -EINVAL;
30068fbff68SSubbaraya Sundeep 	}
30168fbff68SSubbaraya Sundeep 
302d45d8979SChristina Jacob 	if (if_up)
30305c22b54STomasz Duszynski 		dev->netdev_ops->ndo_stop(dev);
304d45d8979SChristina Jacob 
3056cebb6a4SHariprasad Kelam 	qos_txqs = bitmap_weight(pfvf->qos.qos_sq_bmap,
3066cebb6a4SHariprasad Kelam 				 OTX2_QOS_MAX_LEAF_NODES);
3076cebb6a4SHariprasad Kelam 
3086cebb6a4SHariprasad Kelam 	err = otx2_set_real_num_queues(dev, channel->tx_count + qos_txqs,
309d45d8979SChristina Jacob 				       channel->rx_count);
310d45d8979SChristina Jacob 	if (err)
31169f0aeb1SGeetha sowjanya 		return err;
312d45d8979SChristina Jacob 
313d45d8979SChristina Jacob 	pfvf->hw.rx_queues = channel->rx_count;
314d45d8979SChristina Jacob 	pfvf->hw.tx_queues = channel->tx_count;
3156cebb6a4SHariprasad Kelam 	if (pfvf->xdp_prog)
3166cebb6a4SHariprasad Kelam 		pfvf->hw.xdp_queues = channel->rx_count;
317d45d8979SChristina Jacob 
318d45d8979SChristina Jacob 	if (if_up)
31969f0aeb1SGeetha sowjanya 		err = dev->netdev_ops->ndo_open(dev);
320d45d8979SChristina Jacob 
321d45d8979SChristina Jacob 	netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
322d45d8979SChristina Jacob 		    pfvf->hw.tx_queues, pfvf->hw.rx_queues);
323d45d8979SChristina Jacob 
324d45d8979SChristina Jacob 	return err;
325d45d8979SChristina Jacob }
326d45d8979SChristina Jacob 
otx2_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)32775f36270SGeetha sowjanya static void otx2_get_pauseparam(struct net_device *netdev,
32875f36270SGeetha sowjanya 				struct ethtool_pauseparam *pause)
32975f36270SGeetha sowjanya {
33075f36270SGeetha sowjanya 	struct otx2_nic *pfvf = netdev_priv(netdev);
33175f36270SGeetha sowjanya 	struct cgx_pause_frm_cfg *req, *rsp;
33275f36270SGeetha sowjanya 
33305c22b54STomasz Duszynski 	if (is_otx2_lbkvf(pfvf->pdev))
33405c22b54STomasz Duszynski 		return;
33505c22b54STomasz Duszynski 
3366ddf005fSSubbaraya Sundeep 	mutex_lock(&pfvf->mbox.lock);
33775f36270SGeetha sowjanya 	req = otx2_mbox_alloc_msg_cgx_cfg_pause_frm(&pfvf->mbox);
3386ddf005fSSubbaraya Sundeep 	if (!req) {
3396ddf005fSSubbaraya Sundeep 		mutex_unlock(&pfvf->mbox.lock);
34075f36270SGeetha sowjanya 		return;
3416ddf005fSSubbaraya Sundeep 	}
34275f36270SGeetha sowjanya 
34375f36270SGeetha sowjanya 	if (!otx2_sync_mbox_msg(&pfvf->mbox)) {
34475f36270SGeetha sowjanya 		rsp = (struct cgx_pause_frm_cfg *)
34575f36270SGeetha sowjanya 		       otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr);
346*c0f64fd7SDipendra Khadka 		if (IS_ERR(rsp)) {
347*c0f64fd7SDipendra Khadka 			mutex_unlock(&pfvf->mbox.lock);
348*c0f64fd7SDipendra Khadka 			return;
349*c0f64fd7SDipendra Khadka 		}
350*c0f64fd7SDipendra Khadka 
35175f36270SGeetha sowjanya 		pause->rx_pause = rsp->rx_pause;
35275f36270SGeetha sowjanya 		pause->tx_pause = rsp->tx_pause;
35375f36270SGeetha sowjanya 	}
3546ddf005fSSubbaraya Sundeep 	mutex_unlock(&pfvf->mbox.lock);
35575f36270SGeetha sowjanya }
35675f36270SGeetha sowjanya 
otx2_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)35775f36270SGeetha sowjanya static int otx2_set_pauseparam(struct net_device *netdev,
35875f36270SGeetha sowjanya 			       struct ethtool_pauseparam *pause)
35975f36270SGeetha sowjanya {
36075f36270SGeetha sowjanya 	struct otx2_nic *pfvf = netdev_priv(netdev);
36175f36270SGeetha sowjanya 
36275f36270SGeetha sowjanya 	if (pause->autoneg)
36375f36270SGeetha sowjanya 		return -EOPNOTSUPP;
36475f36270SGeetha sowjanya 
36505c22b54STomasz Duszynski 	if (is_otx2_lbkvf(pfvf->pdev))
36605c22b54STomasz Duszynski 		return -EOPNOTSUPP;
36705c22b54STomasz Duszynski 
36875f36270SGeetha sowjanya 	if (pause->rx_pause)
36975f36270SGeetha sowjanya 		pfvf->flags |= OTX2_FLAG_RX_PAUSE_ENABLED;
37075f36270SGeetha sowjanya 	else
37175f36270SGeetha sowjanya 		pfvf->flags &= ~OTX2_FLAG_RX_PAUSE_ENABLED;
37275f36270SGeetha sowjanya 
37375f36270SGeetha sowjanya 	if (pause->tx_pause)
37475f36270SGeetha sowjanya 		pfvf->flags |= OTX2_FLAG_TX_PAUSE_ENABLED;
37575f36270SGeetha sowjanya 	else
37675f36270SGeetha sowjanya 		pfvf->flags &= ~OTX2_FLAG_TX_PAUSE_ENABLED;
37775f36270SGeetha sowjanya 
37875f36270SGeetha sowjanya 	return otx2_config_pause_frm(pfvf);
37975f36270SGeetha sowjanya }
38075f36270SGeetha sowjanya 
otx2_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)381d45d8979SChristina Jacob static void otx2_get_ringparam(struct net_device *netdev,
38274624944SHao Chen 			       struct ethtool_ringparam *ring,
38374624944SHao Chen 			       struct kernel_ethtool_ringparam *kernel_ring,
38474624944SHao Chen 			       struct netlink_ext_ack *extack)
385d45d8979SChristina Jacob {
386d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
387d45d8979SChristina Jacob 	struct otx2_qset *qs = &pfvf->qset;
388d45d8979SChristina Jacob 
389d45d8979SChristina Jacob 	ring->rx_max_pending = Q_COUNT(Q_SIZE_MAX);
390d45d8979SChristina Jacob 	ring->rx_pending = qs->rqe_cnt ? qs->rqe_cnt : Q_COUNT(Q_SIZE_256);
391d45d8979SChristina Jacob 	ring->tx_max_pending = Q_COUNT(Q_SIZE_MAX);
392d45d8979SChristina Jacob 	ring->tx_pending = qs->sqe_cnt ? qs->sqe_cnt : Q_COUNT(Q_SIZE_4K);
393a989eb66SSubbaraya Sundeep 	kernel_ring->rx_buf_len = pfvf->hw.rbuf_len;
39468258596SSubbaraya Sundeep 	kernel_ring->cqe_size = pfvf->hw.xqe_size;
395d45d8979SChristina Jacob }
396d45d8979SChristina Jacob 
otx2_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)397d45d8979SChristina Jacob static int otx2_set_ringparam(struct net_device *netdev,
39874624944SHao Chen 			      struct ethtool_ringparam *ring,
39974624944SHao Chen 			      struct kernel_ethtool_ringparam *kernel_ring,
40074624944SHao Chen 			      struct netlink_ext_ack *extack)
401d45d8979SChristina Jacob {
402d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
403a989eb66SSubbaraya Sundeep 	u32 rx_buf_len = kernel_ring->rx_buf_len;
404a989eb66SSubbaraya Sundeep 	u32 old_rx_buf_len = pfvf->hw.rbuf_len;
40568258596SSubbaraya Sundeep 	u32 xqe_size = kernel_ring->cqe_size;
406d45d8979SChristina Jacob 	bool if_up = netif_running(netdev);
407d45d8979SChristina Jacob 	struct otx2_qset *qs = &pfvf->qset;
408d45d8979SChristina Jacob 	u32 rx_count, tx_count;
409d45d8979SChristina Jacob 
410d45d8979SChristina Jacob 	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
411d45d8979SChristina Jacob 		return -EINVAL;
412d45d8979SChristina Jacob 
413a989eb66SSubbaraya Sundeep 	/* Hardware supports max size of 32k for a receive buffer
414a989eb66SSubbaraya Sundeep 	 * and 1536 is typical ethernet frame size.
415a989eb66SSubbaraya Sundeep 	 */
416a989eb66SSubbaraya Sundeep 	if (rx_buf_len && (rx_buf_len < 1536 || rx_buf_len > 32768)) {
417a989eb66SSubbaraya Sundeep 		netdev_err(netdev,
418a989eb66SSubbaraya Sundeep 			   "Receive buffer range is 1536 - 32768");
419a989eb66SSubbaraya Sundeep 		return -EINVAL;
420a989eb66SSubbaraya Sundeep 	}
421a989eb66SSubbaraya Sundeep 
42268258596SSubbaraya Sundeep 	if (xqe_size != 128 && xqe_size != 512) {
42368258596SSubbaraya Sundeep 		netdev_err(netdev,
42468258596SSubbaraya Sundeep 			   "Completion event size must be 128 or 512");
42568258596SSubbaraya Sundeep 		return -EINVAL;
42668258596SSubbaraya Sundeep 	}
42768258596SSubbaraya Sundeep 
428d45d8979SChristina Jacob 	/* Permitted lengths are 16 64 256 1K 4K 16K 64K 256K 1M  */
429d45d8979SChristina Jacob 	rx_count = ring->rx_pending;
430d45d8979SChristina Jacob 	/* On some silicon variants a skid or reserved CQEs are
431d45d8979SChristina Jacob 	 * needed to avoid CQ overflow.
432d45d8979SChristina Jacob 	 */
433d45d8979SChristina Jacob 	if (rx_count < pfvf->hw.rq_skid)
434d45d8979SChristina Jacob 		rx_count =  pfvf->hw.rq_skid;
435d45d8979SChristina Jacob 	rx_count = Q_COUNT(Q_SIZE(rx_count, 3));
436d45d8979SChristina Jacob 
437d45d8979SChristina Jacob 	/* Due pipelining impact minimum 2000 unused SQ CQE's
438d45d8979SChristina Jacob 	 * need to be maintained to avoid CQ overflow, hence the
439d45d8979SChristina Jacob 	 * minimum 4K size.
440d45d8979SChristina Jacob 	 */
441d45d8979SChristina Jacob 	tx_count = clamp_t(u32, ring->tx_pending,
442d45d8979SChristina Jacob 			   Q_COUNT(Q_SIZE_4K), Q_COUNT(Q_SIZE_MAX));
443d45d8979SChristina Jacob 	tx_count = Q_COUNT(Q_SIZE(tx_count, 3));
444d45d8979SChristina Jacob 
445a989eb66SSubbaraya Sundeep 	if (tx_count == qs->sqe_cnt && rx_count == qs->rqe_cnt &&
44668258596SSubbaraya Sundeep 	    rx_buf_len == old_rx_buf_len && xqe_size == pfvf->hw.xqe_size)
447d45d8979SChristina Jacob 		return 0;
448d45d8979SChristina Jacob 
449d45d8979SChristina Jacob 	if (if_up)
45005c22b54STomasz Duszynski 		netdev->netdev_ops->ndo_stop(netdev);
451d45d8979SChristina Jacob 
452d45d8979SChristina Jacob 	/* Assigned to the nearest possible exponent. */
453d45d8979SChristina Jacob 	qs->sqe_cnt = tx_count;
454d45d8979SChristina Jacob 	qs->rqe_cnt = rx_count;
455d45d8979SChristina Jacob 
456a989eb66SSubbaraya Sundeep 	pfvf->hw.rbuf_len = rx_buf_len;
45768258596SSubbaraya Sundeep 	pfvf->hw.xqe_size = xqe_size;
458a989eb66SSubbaraya Sundeep 
459d45d8979SChristina Jacob 	if (if_up)
46069f0aeb1SGeetha sowjanya 		return netdev->netdev_ops->ndo_open(netdev);
46105c22b54STomasz Duszynski 
462d45d8979SChristina Jacob 	return 0;
463d45d8979SChristina Jacob }
464d45d8979SChristina Jacob 
otx2_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * cmd,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)465d45d8979SChristina Jacob static int otx2_get_coalesce(struct net_device *netdev,
466f3ccfda1SYufeng Mo 			     struct ethtool_coalesce *cmd,
467f3ccfda1SYufeng Mo 			     struct kernel_ethtool_coalesce *kernel_coal,
468f3ccfda1SYufeng Mo 			     struct netlink_ext_ack *extack)
469d45d8979SChristina Jacob {
470d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
471d45d8979SChristina Jacob 	struct otx2_hw *hw = &pfvf->hw;
472d45d8979SChristina Jacob 
473d45d8979SChristina Jacob 	cmd->rx_coalesce_usecs = hw->cq_time_wait;
474d45d8979SChristina Jacob 	cmd->rx_max_coalesced_frames = hw->cq_ecount_wait;
475d45d8979SChristina Jacob 	cmd->tx_coalesce_usecs = hw->cq_time_wait;
476d45d8979SChristina Jacob 	cmd->tx_max_coalesced_frames = hw->cq_ecount_wait;
4776e144b47SSuman Ghosh 	if ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) ==
4786e144b47SSuman Ghosh 			OTX2_FLAG_ADPTV_INT_COAL_ENABLED) {
4796e144b47SSuman Ghosh 		cmd->use_adaptive_rx_coalesce = 1;
4806e144b47SSuman Ghosh 		cmd->use_adaptive_tx_coalesce = 1;
4816e144b47SSuman Ghosh 	} else {
4826e144b47SSuman Ghosh 		cmd->use_adaptive_rx_coalesce = 0;
4836e144b47SSuman Ghosh 		cmd->use_adaptive_tx_coalesce = 0;
4846e144b47SSuman Ghosh 	}
485d45d8979SChristina Jacob 
486d45d8979SChristina Jacob 	return 0;
487d45d8979SChristina Jacob }
488d45d8979SChristina Jacob 
otx2_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)489d45d8979SChristina Jacob static int otx2_set_coalesce(struct net_device *netdev,
490f3ccfda1SYufeng Mo 			     struct ethtool_coalesce *ec,
491f3ccfda1SYufeng Mo 			     struct kernel_ethtool_coalesce *kernel_coal,
492f3ccfda1SYufeng Mo 			     struct netlink_ext_ack *extack)
493d45d8979SChristina Jacob {
494d45d8979SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
495d45d8979SChristina Jacob 	struct otx2_hw *hw = &pfvf->hw;
4966e144b47SSuman Ghosh 	u8 priv_coalesce_status;
497d45d8979SChristina Jacob 	int qidx;
498d45d8979SChristina Jacob 
499d45d8979SChristina Jacob 	if (!ec->rx_max_coalesced_frames || !ec->tx_max_coalesced_frames)
500d45d8979SChristina Jacob 		return 0;
501d45d8979SChristina Jacob 
5026e144b47SSuman Ghosh 	if (ec->use_adaptive_rx_coalesce != ec->use_adaptive_tx_coalesce) {
5036e144b47SSuman Ghosh 		netdev_err(netdev,
5046e144b47SSuman Ghosh 			   "adaptive-rx should be same as adaptive-tx");
5056e144b47SSuman Ghosh 		return -EINVAL;
5066e144b47SSuman Ghosh 	}
5076e144b47SSuman Ghosh 
5086e144b47SSuman Ghosh 	/* Check and update coalesce status */
5096e144b47SSuman Ghosh 	if ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) ==
5106e144b47SSuman Ghosh 			OTX2_FLAG_ADPTV_INT_COAL_ENABLED) {
5116e144b47SSuman Ghosh 		priv_coalesce_status = 1;
5126e144b47SSuman Ghosh 		if (!ec->use_adaptive_rx_coalesce)
5136e144b47SSuman Ghosh 			pfvf->flags &= ~OTX2_FLAG_ADPTV_INT_COAL_ENABLED;
5146e144b47SSuman Ghosh 	} else {
5156e144b47SSuman Ghosh 		priv_coalesce_status = 0;
5166e144b47SSuman Ghosh 		if (ec->use_adaptive_rx_coalesce)
5176e144b47SSuman Ghosh 			pfvf->flags |= OTX2_FLAG_ADPTV_INT_COAL_ENABLED;
5186e144b47SSuman Ghosh 	}
5196e144b47SSuman Ghosh 
520d45d8979SChristina Jacob 	/* 'cq_time_wait' is 8bit and is in multiple of 100ns,
521d45d8979SChristina Jacob 	 * so clamp the user given value to the range of 1 to 25usec.
522d45d8979SChristina Jacob 	 */
523d45d8979SChristina Jacob 	ec->rx_coalesce_usecs = clamp_t(u32, ec->rx_coalesce_usecs,
524d45d8979SChristina Jacob 					1, CQ_TIMER_THRESH_MAX);
525d45d8979SChristina Jacob 	ec->tx_coalesce_usecs = clamp_t(u32, ec->tx_coalesce_usecs,
526d45d8979SChristina Jacob 					1, CQ_TIMER_THRESH_MAX);
527d45d8979SChristina Jacob 
528d45d8979SChristina Jacob 	/* Rx and Tx are mapped to same CQ, check which one
529d45d8979SChristina Jacob 	 * is changed, if both then choose the min.
530d45d8979SChristina Jacob 	 */
531d45d8979SChristina Jacob 	if (hw->cq_time_wait == ec->rx_coalesce_usecs)
532d45d8979SChristina Jacob 		hw->cq_time_wait = ec->tx_coalesce_usecs;
533d45d8979SChristina Jacob 	else if (hw->cq_time_wait == ec->tx_coalesce_usecs)
534d45d8979SChristina Jacob 		hw->cq_time_wait = ec->rx_coalesce_usecs;
535d45d8979SChristina Jacob 	else
536d45d8979SChristina Jacob 		hw->cq_time_wait = min_t(u8, ec->rx_coalesce_usecs,
537d45d8979SChristina Jacob 					 ec->tx_coalesce_usecs);
538d45d8979SChristina Jacob 
539d45d8979SChristina Jacob 	/* Max ecount_wait supported is 16bit,
540d45d8979SChristina Jacob 	 * so clamp the user given value to the range of 1 to 64k.
541d45d8979SChristina Jacob 	 */
542d45d8979SChristina Jacob 	ec->rx_max_coalesced_frames = clamp_t(u32, ec->rx_max_coalesced_frames,
5436e144b47SSuman Ghosh 					      1, NAPI_POLL_WEIGHT);
544d45d8979SChristina Jacob 	ec->tx_max_coalesced_frames = clamp_t(u32, ec->tx_max_coalesced_frames,
5456e144b47SSuman Ghosh 					      1, NAPI_POLL_WEIGHT);
546d45d8979SChristina Jacob 
547d45d8979SChristina Jacob 	/* Rx and Tx are mapped to same CQ, check which one
548d45d8979SChristina Jacob 	 * is changed, if both then choose the min.
549d45d8979SChristina Jacob 	 */
550d45d8979SChristina Jacob 	if (hw->cq_ecount_wait == ec->rx_max_coalesced_frames)
551d45d8979SChristina Jacob 		hw->cq_ecount_wait = ec->tx_max_coalesced_frames;
552d45d8979SChristina Jacob 	else if (hw->cq_ecount_wait == ec->tx_max_coalesced_frames)
553d45d8979SChristina Jacob 		hw->cq_ecount_wait = ec->rx_max_coalesced_frames;
554d45d8979SChristina Jacob 	else
555d45d8979SChristina Jacob 		hw->cq_ecount_wait = min_t(u16, ec->rx_max_coalesced_frames,
556d45d8979SChristina Jacob 					   ec->tx_max_coalesced_frames);
557d45d8979SChristina Jacob 
5586e144b47SSuman Ghosh 	/* Reset 'cq_time_wait' and 'cq_ecount_wait' to
5596e144b47SSuman Ghosh 	 * default values if coalesce status changed from
5606e144b47SSuman Ghosh 	 * 'on' to 'off'.
5616e144b47SSuman Ghosh 	 */
5626e144b47SSuman Ghosh 	if (priv_coalesce_status &&
5636e144b47SSuman Ghosh 	    ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) !=
5646e144b47SSuman Ghosh 	     OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {
5656e144b47SSuman Ghosh 		hw->cq_time_wait = CQ_TIMER_THRESH_DEFAULT;
5666e144b47SSuman Ghosh 		hw->cq_ecount_wait = CQ_CQE_THRESH_DEFAULT;
5676e144b47SSuman Ghosh 	}
5686e144b47SSuman Ghosh 
569d45d8979SChristina Jacob 	if (netif_running(netdev)) {
570d45d8979SChristina Jacob 		for (qidx = 0; qidx < pfvf->hw.cint_cnt; qidx++)
571d45d8979SChristina Jacob 			otx2_config_irq_coalescing(pfvf, qidx);
572d45d8979SChristina Jacob 	}
573d45d8979SChristina Jacob 
574d45d8979SChristina Jacob 	return 0;
575d45d8979SChristina Jacob }
576d45d8979SChristina Jacob 
otx2_get_rss_hash_opts(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc)5776e92d71bSSunil Goutham static int otx2_get_rss_hash_opts(struct otx2_nic *pfvf,
5786e92d71bSSunil Goutham 				  struct ethtool_rxnfc *nfc)
5796e92d71bSSunil Goutham {
5806e92d71bSSunil Goutham 	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
5816e92d71bSSunil Goutham 
5826e92d71bSSunil Goutham 	if (!(rss->flowkey_cfg &
5836e92d71bSSunil Goutham 	    (NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6)))
5846e92d71bSSunil Goutham 		return 0;
5856e92d71bSSunil Goutham 
5866e92d71bSSunil Goutham 	/* Mimimum is IPv4 and IPv6, SIP/DIP */
5876e92d71bSSunil Goutham 	nfc->data = RXH_IP_SRC | RXH_IP_DST;
588a55ff8efSGeorge Cherian 	if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_VLAN)
589a55ff8efSGeorge Cherian 		nfc->data |= RXH_VLAN;
5906e92d71bSSunil Goutham 
5916e92d71bSSunil Goutham 	switch (nfc->flow_type) {
5926e92d71bSSunil Goutham 	case TCP_V4_FLOW:
5936e92d71bSSunil Goutham 	case TCP_V6_FLOW:
5946e92d71bSSunil Goutham 		if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_TCP)
5956e92d71bSSunil Goutham 			nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
5966e92d71bSSunil Goutham 		break;
5976e92d71bSSunil Goutham 	case UDP_V4_FLOW:
5986e92d71bSSunil Goutham 	case UDP_V6_FLOW:
5996e92d71bSSunil Goutham 		if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_UDP)
6006e92d71bSSunil Goutham 			nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
6016e92d71bSSunil Goutham 		break;
6026e92d71bSSunil Goutham 	case SCTP_V4_FLOW:
6036e92d71bSSunil Goutham 	case SCTP_V6_FLOW:
6046e92d71bSSunil Goutham 		if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_SCTP)
6056e92d71bSSunil Goutham 			nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
6066e92d71bSSunil Goutham 		break;
6076e92d71bSSunil Goutham 	case AH_ESP_V4_FLOW:
608b9b7421aSSubbaraya Sundeep 	case AH_ESP_V6_FLOW:
609b9b7421aSSubbaraya Sundeep 		if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_ESP)
610b9b7421aSSubbaraya Sundeep 			nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
611b9b7421aSSubbaraya Sundeep 		break;
6126e92d71bSSunil Goutham 	case AH_V4_FLOW:
6136e92d71bSSunil Goutham 	case ESP_V4_FLOW:
6146e92d71bSSunil Goutham 	case IPV4_FLOW:
615b9b7421aSSubbaraya Sundeep 		break;
6166e92d71bSSunil Goutham 	case AH_V6_FLOW:
6176e92d71bSSunil Goutham 	case ESP_V6_FLOW:
6186e92d71bSSunil Goutham 	case IPV6_FLOW:
6196e92d71bSSunil Goutham 		break;
6206e92d71bSSunil Goutham 	default:
6216e92d71bSSunil Goutham 		return -EINVAL;
6226e92d71bSSunil Goutham 	}
623b9b7421aSSubbaraya Sundeep 
6246e92d71bSSunil Goutham 	return 0;
6256e92d71bSSunil Goutham }
6266e92d71bSSunil Goutham 
otx2_set_rss_hash_opts(struct otx2_nic * pfvf,struct ethtool_rxnfc * nfc)6276e92d71bSSunil Goutham static int otx2_set_rss_hash_opts(struct otx2_nic *pfvf,
6286e92d71bSSunil Goutham 				  struct ethtool_rxnfc *nfc)
6296e92d71bSSunil Goutham {
6306e92d71bSSunil Goutham 	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
6316e92d71bSSunil Goutham 	u32 rxh_l4 = RXH_L4_B_0_1 | RXH_L4_B_2_3;
6326e92d71bSSunil Goutham 	u32 rss_cfg = rss->flowkey_cfg;
6336e92d71bSSunil Goutham 
6346e92d71bSSunil Goutham 	if (!rss->enable) {
6356e92d71bSSunil Goutham 		netdev_err(pfvf->netdev,
6366e92d71bSSunil Goutham 			   "RSS is disabled, cannot change settings\n");
6376e92d71bSSunil Goutham 		return -EIO;
6386e92d71bSSunil Goutham 	}
6396e92d71bSSunil Goutham 
6406e92d71bSSunil Goutham 	/* Mimimum is IPv4 and IPv6, SIP/DIP */
6416e92d71bSSunil Goutham 	if (!(nfc->data & RXH_IP_SRC) || !(nfc->data & RXH_IP_DST))
6426e92d71bSSunil Goutham 		return -EINVAL;
6436e92d71bSSunil Goutham 
644a55ff8efSGeorge Cherian 	if (nfc->data & RXH_VLAN)
645a55ff8efSGeorge Cherian 		rss_cfg |=  NIX_FLOW_KEY_TYPE_VLAN;
646a55ff8efSGeorge Cherian 	else
647a55ff8efSGeorge Cherian 		rss_cfg &= ~NIX_FLOW_KEY_TYPE_VLAN;
648a55ff8efSGeorge Cherian 
6496e92d71bSSunil Goutham 	switch (nfc->flow_type) {
6506e92d71bSSunil Goutham 	case TCP_V4_FLOW:
6516e92d71bSSunil Goutham 	case TCP_V6_FLOW:
6526e92d71bSSunil Goutham 		/* Different config for v4 and v6 is not supported.
6536e92d71bSSunil Goutham 		 * Both of them have to be either 4-tuple or 2-tuple.
6546e92d71bSSunil Goutham 		 */
6556e92d71bSSunil Goutham 		switch (nfc->data & rxh_l4) {
6566e92d71bSSunil Goutham 		case 0:
6576e92d71bSSunil Goutham 			rss_cfg &= ~NIX_FLOW_KEY_TYPE_TCP;
6586e92d71bSSunil Goutham 			break;
6596e92d71bSSunil Goutham 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
6606e92d71bSSunil Goutham 			rss_cfg |= NIX_FLOW_KEY_TYPE_TCP;
6616e92d71bSSunil Goutham 			break;
6626e92d71bSSunil Goutham 		default:
6636e92d71bSSunil Goutham 			return -EINVAL;
6646e92d71bSSunil Goutham 		}
6656e92d71bSSunil Goutham 		break;
6666e92d71bSSunil Goutham 	case UDP_V4_FLOW:
6676e92d71bSSunil Goutham 	case UDP_V6_FLOW:
6686e92d71bSSunil Goutham 		switch (nfc->data & rxh_l4) {
6696e92d71bSSunil Goutham 		case 0:
6706e92d71bSSunil Goutham 			rss_cfg &= ~NIX_FLOW_KEY_TYPE_UDP;
6716e92d71bSSunil Goutham 			break;
6726e92d71bSSunil Goutham 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
6736e92d71bSSunil Goutham 			rss_cfg |= NIX_FLOW_KEY_TYPE_UDP;
6746e92d71bSSunil Goutham 			break;
6756e92d71bSSunil Goutham 		default:
6766e92d71bSSunil Goutham 			return -EINVAL;
6776e92d71bSSunil Goutham 		}
6786e92d71bSSunil Goutham 		break;
6796e92d71bSSunil Goutham 	case SCTP_V4_FLOW:
6806e92d71bSSunil Goutham 	case SCTP_V6_FLOW:
6816e92d71bSSunil Goutham 		switch (nfc->data & rxh_l4) {
6826e92d71bSSunil Goutham 		case 0:
6836e92d71bSSunil Goutham 			rss_cfg &= ~NIX_FLOW_KEY_TYPE_SCTP;
6846e92d71bSSunil Goutham 			break;
6856e92d71bSSunil Goutham 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
6866e92d71bSSunil Goutham 			rss_cfg |= NIX_FLOW_KEY_TYPE_SCTP;
6876e92d71bSSunil Goutham 			break;
6886e92d71bSSunil Goutham 		default:
6896e92d71bSSunil Goutham 			return -EINVAL;
6906e92d71bSSunil Goutham 		}
6916e92d71bSSunil Goutham 		break;
692b9b7421aSSubbaraya Sundeep 	case AH_ESP_V4_FLOW:
693b9b7421aSSubbaraya Sundeep 	case AH_ESP_V6_FLOW:
694b9b7421aSSubbaraya Sundeep 		switch (nfc->data & rxh_l4) {
695b9b7421aSSubbaraya Sundeep 		case 0:
696b9b7421aSSubbaraya Sundeep 			rss_cfg &= ~(NIX_FLOW_KEY_TYPE_ESP |
697b9b7421aSSubbaraya Sundeep 				     NIX_FLOW_KEY_TYPE_AH);
698b9b7421aSSubbaraya Sundeep 			rss_cfg |= NIX_FLOW_KEY_TYPE_VLAN |
699b9b7421aSSubbaraya Sundeep 				   NIX_FLOW_KEY_TYPE_IPV4_PROTO;
700b9b7421aSSubbaraya Sundeep 			break;
701b9b7421aSSubbaraya Sundeep 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
702b9b7421aSSubbaraya Sundeep 			/* If VLAN hashing is also requested for ESP then do not
703b9b7421aSSubbaraya Sundeep 			 * allow because of hardware 40 bytes flow key limit.
704b9b7421aSSubbaraya Sundeep 			 */
705b9b7421aSSubbaraya Sundeep 			if (rss_cfg & NIX_FLOW_KEY_TYPE_VLAN) {
706b9b7421aSSubbaraya Sundeep 				netdev_err(pfvf->netdev,
707b9b7421aSSubbaraya Sundeep 					   "RSS hash of ESP or AH with VLAN is not supported\n");
708b9b7421aSSubbaraya Sundeep 				return -EOPNOTSUPP;
709b9b7421aSSubbaraya Sundeep 			}
710b9b7421aSSubbaraya Sundeep 
711b9b7421aSSubbaraya Sundeep 			rss_cfg |= NIX_FLOW_KEY_TYPE_ESP | NIX_FLOW_KEY_TYPE_AH;
712b9b7421aSSubbaraya Sundeep 			/* Disable IPv4 proto hashing since IPv6 SA+DA(32 bytes)
713b9b7421aSSubbaraya Sundeep 			 * and ESP SPI+sequence(8 bytes) uses hardware maximum
714b9b7421aSSubbaraya Sundeep 			 * limit of 40 byte flow key.
715b9b7421aSSubbaraya Sundeep 			 */
716b9b7421aSSubbaraya Sundeep 			rss_cfg &= ~NIX_FLOW_KEY_TYPE_IPV4_PROTO;
717b9b7421aSSubbaraya Sundeep 			break;
718b9b7421aSSubbaraya Sundeep 		default:
719b9b7421aSSubbaraya Sundeep 			return -EINVAL;
720b9b7421aSSubbaraya Sundeep 		}
721b9b7421aSSubbaraya Sundeep 		break;
7226e92d71bSSunil Goutham 	case IPV4_FLOW:
7236e92d71bSSunil Goutham 	case IPV6_FLOW:
7246e92d71bSSunil Goutham 		rss_cfg = NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6;
7256e92d71bSSunil Goutham 		break;
7266e92d71bSSunil Goutham 	default:
7276e92d71bSSunil Goutham 		return -EINVAL;
7286e92d71bSSunil Goutham 	}
7296e92d71bSSunil Goutham 
7306e92d71bSSunil Goutham 	rss->flowkey_cfg = rss_cfg;
7316e92d71bSSunil Goutham 	otx2_set_flowkey_cfg(pfvf);
7326e92d71bSSunil Goutham 	return 0;
7336e92d71bSSunil Goutham }
7346e92d71bSSunil Goutham 
otx2_get_rxnfc(struct net_device * dev,struct ethtool_rxnfc * nfc,u32 * rules)7356e92d71bSSunil Goutham static int otx2_get_rxnfc(struct net_device *dev,
7366e92d71bSSunil Goutham 			  struct ethtool_rxnfc *nfc, u32 *rules)
7376e92d71bSSunil Goutham {
7383cffaed2SRakesh Babu 	bool ntuple = !!(dev->features & NETIF_F_NTUPLE);
7396e92d71bSSunil Goutham 	struct otx2_nic *pfvf = netdev_priv(dev);
7406e92d71bSSunil Goutham 	int ret = -EOPNOTSUPP;
7416e92d71bSSunil Goutham 
7426e92d71bSSunil Goutham 	switch (nfc->cmd) {
7436e92d71bSSunil Goutham 	case ETHTOOL_GRXRINGS:
7446e92d71bSSunil Goutham 		nfc->data = pfvf->hw.rx_queues;
7456e92d71bSSunil Goutham 		ret = 0;
7466e92d71bSSunil Goutham 		break;
747f0a1913fSSubbaraya Sundeep 	case ETHTOOL_GRXCLSRLCNT:
7483cffaed2SRakesh Babu 		if (netif_running(dev) && ntuple) {
749f0a1913fSSubbaraya Sundeep 			nfc->rule_cnt = pfvf->flow_cfg->nr_flows;
750f0a1913fSSubbaraya Sundeep 			ret = 0;
7513cffaed2SRakesh Babu 		}
752f0a1913fSSubbaraya Sundeep 		break;
753f0a1913fSSubbaraya Sundeep 	case ETHTOOL_GRXCLSRULE:
7543cffaed2SRakesh Babu 		if (netif_running(dev) && ntuple)
755f0a1913fSSubbaraya Sundeep 			ret = otx2_get_flow(pfvf, nfc,  nfc->fs.location);
756f0a1913fSSubbaraya Sundeep 		break;
757f0a1913fSSubbaraya Sundeep 	case ETHTOOL_GRXCLSRLALL:
7583cffaed2SRakesh Babu 		if (netif_running(dev) && ntuple)
759f0a1913fSSubbaraya Sundeep 			ret = otx2_get_all_flows(pfvf, nfc, rules);
760f0a1913fSSubbaraya Sundeep 		break;
7616e92d71bSSunil Goutham 	case ETHTOOL_GRXFH:
7626e92d71bSSunil Goutham 		return otx2_get_rss_hash_opts(pfvf, nfc);
7636e92d71bSSunil Goutham 	default:
7646e92d71bSSunil Goutham 		break;
7656e92d71bSSunil Goutham 	}
7666e92d71bSSunil Goutham 	return ret;
7676e92d71bSSunil Goutham }
7686e92d71bSSunil Goutham 
otx2_set_rxnfc(struct net_device * dev,struct ethtool_rxnfc * nfc)7696e92d71bSSunil Goutham static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc)
7706e92d71bSSunil Goutham {
771f0a1913fSSubbaraya Sundeep 	bool ntuple = !!(dev->features & NETIF_F_NTUPLE);
772f0a1913fSSubbaraya Sundeep 	struct otx2_nic *pfvf = netdev_priv(dev);
773f0a1913fSSubbaraya Sundeep 	int ret = -EOPNOTSUPP;
774f0a1913fSSubbaraya Sundeep 
775ec87f054SSuman Ghosh 	pfvf->flow_cfg->ntuple = ntuple;
776f0a1913fSSubbaraya Sundeep 	switch (nfc->cmd) {
777f0a1913fSSubbaraya Sundeep 	case ETHTOOL_SRXFH:
778f0a1913fSSubbaraya Sundeep 		ret = otx2_set_rss_hash_opts(pfvf, nfc);
779f0a1913fSSubbaraya Sundeep 		break;
780f0a1913fSSubbaraya Sundeep 	case ETHTOOL_SRXCLSRLINS:
781f0a1913fSSubbaraya Sundeep 		if (netif_running(dev) && ntuple)
78281a43620SGeetha sowjanya 			ret = otx2_add_flow(pfvf, nfc);
783f0a1913fSSubbaraya Sundeep 		break;
784f0a1913fSSubbaraya Sundeep 	case ETHTOOL_SRXCLSRLDEL:
785f0a1913fSSubbaraya Sundeep 		if (netif_running(dev) && ntuple)
786f0a1913fSSubbaraya Sundeep 			ret = otx2_remove_flow(pfvf, nfc->fs.location);
787f0a1913fSSubbaraya Sundeep 		break;
788f0a1913fSSubbaraya Sundeep 	default:
789f0a1913fSSubbaraya Sundeep 		break;
790f0a1913fSSubbaraya Sundeep 	}
791f0a1913fSSubbaraya Sundeep 
792f0a1913fSSubbaraya Sundeep 	return ret;
793f0a1913fSSubbaraya Sundeep }
794f0a1913fSSubbaraya Sundeep 
otx2_get_rxfh_key_size(struct net_device * netdev)7956e92d71bSSunil Goutham static u32 otx2_get_rxfh_key_size(struct net_device *netdev)
7966e92d71bSSunil Goutham {
7976e92d71bSSunil Goutham 	struct otx2_nic *pfvf = netdev_priv(netdev);
7986e92d71bSSunil Goutham 	struct otx2_rss_info *rss;
7996e92d71bSSunil Goutham 
8006e92d71bSSunil Goutham 	rss = &pfvf->hw.rss_info;
8016e92d71bSSunil Goutham 
8026e92d71bSSunil Goutham 	return sizeof(rss->key);
8036e92d71bSSunil Goutham }
8046e92d71bSSunil Goutham 
otx2_get_rxfh_indir_size(struct net_device * dev)8056e92d71bSSunil Goutham static u32 otx2_get_rxfh_indir_size(struct net_device *dev)
8066e92d71bSSunil Goutham {
80781a43620SGeetha sowjanya 	return  MAX_RSS_INDIR_TBL_SIZE;
8086e92d71bSSunil Goutham }
8096e92d71bSSunil Goutham 
otx2_rss_ctx_delete(struct otx2_nic * pfvf,int ctx_id)81081a43620SGeetha sowjanya static int otx2_rss_ctx_delete(struct otx2_nic *pfvf, int ctx_id)
8116e92d71bSSunil Goutham {
81281a43620SGeetha sowjanya 	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
8136e92d71bSSunil Goutham 
81481a43620SGeetha sowjanya 	otx2_rss_ctx_flow_del(pfvf, ctx_id);
81581a43620SGeetha sowjanya 	kfree(rss->rss_ctx[ctx_id]);
81681a43620SGeetha sowjanya 	rss->rss_ctx[ctx_id] = NULL;
8176e92d71bSSunil Goutham 
8186e92d71bSSunil Goutham 	return 0;
8196e92d71bSSunil Goutham }
8206e92d71bSSunil Goutham 
otx2_rss_ctx_create(struct otx2_nic * pfvf,u32 * rss_context)82181a43620SGeetha sowjanya static int otx2_rss_ctx_create(struct otx2_nic *pfvf,
82281a43620SGeetha sowjanya 			       u32 *rss_context)
82381a43620SGeetha sowjanya {
82481a43620SGeetha sowjanya 	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
82581a43620SGeetha sowjanya 	u8 ctx;
82681a43620SGeetha sowjanya 
82781a43620SGeetha sowjanya 	for (ctx = 0; ctx < MAX_RSS_GROUPS; ctx++) {
82881a43620SGeetha sowjanya 		if (!rss->rss_ctx[ctx])
82981a43620SGeetha sowjanya 			break;
83081a43620SGeetha sowjanya 	}
83181a43620SGeetha sowjanya 	if (ctx == MAX_RSS_GROUPS)
83281a43620SGeetha sowjanya 		return -EINVAL;
83381a43620SGeetha sowjanya 
83481a43620SGeetha sowjanya 	rss->rss_ctx[ctx] = kzalloc(sizeof(*rss->rss_ctx[ctx]), GFP_KERNEL);
83581a43620SGeetha sowjanya 	if (!rss->rss_ctx[ctx])
83681a43620SGeetha sowjanya 		return -ENOMEM;
83781a43620SGeetha sowjanya 	*rss_context = ctx;
83881a43620SGeetha sowjanya 
83981a43620SGeetha sowjanya 	return 0;
84081a43620SGeetha sowjanya }
84181a43620SGeetha sowjanya 
84281a43620SGeetha sowjanya /* RSS context configuration */
otx2_set_rxfh_context(struct net_device * dev,const u32 * indir,const u8 * hkey,const u8 hfunc,u32 * rss_context,bool delete)84381a43620SGeetha sowjanya static int otx2_set_rxfh_context(struct net_device *dev, const u32 *indir,
84481a43620SGeetha sowjanya 				 const u8 *hkey, const u8 hfunc,
84581a43620SGeetha sowjanya 				 u32 *rss_context, bool delete)
8466e92d71bSSunil Goutham {
8476e92d71bSSunil Goutham 	struct otx2_nic *pfvf = netdev_priv(dev);
84881a43620SGeetha sowjanya 	struct otx2_rss_ctx *rss_ctx;
8496e92d71bSSunil Goutham 	struct otx2_rss_info *rss;
85081a43620SGeetha sowjanya 	int ret, idx;
8516e92d71bSSunil Goutham 
8526e92d71bSSunil Goutham 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
8536e92d71bSSunil Goutham 		return -EOPNOTSUPP;
8546e92d71bSSunil Goutham 
855e5cc361eSDan Carpenter 	if (*rss_context != ETH_RXFH_CONTEXT_ALLOC &&
856e5cc361eSDan Carpenter 	    *rss_context >= MAX_RSS_GROUPS)
857e5cc361eSDan Carpenter 		return -EINVAL;
858e5cc361eSDan Carpenter 
8596e92d71bSSunil Goutham 	rss = &pfvf->hw.rss_info;
8606e92d71bSSunil Goutham 
8616e92d71bSSunil Goutham 	if (!rss->enable) {
8626e92d71bSSunil Goutham 		netdev_err(dev, "RSS is disabled, cannot change settings\n");
8636e92d71bSSunil Goutham 		return -EIO;
8646e92d71bSSunil Goutham 	}
8656e92d71bSSunil Goutham 
8666e92d71bSSunil Goutham 	if (hkey) {
8676e92d71bSSunil Goutham 		memcpy(rss->key, hkey, sizeof(rss->key));
8686e92d71bSSunil Goutham 		otx2_set_rss_key(pfvf);
8696e92d71bSSunil Goutham 	}
87081a43620SGeetha sowjanya 	if (delete)
87181a43620SGeetha sowjanya 		return otx2_rss_ctx_delete(pfvf, *rss_context);
8726e92d71bSSunil Goutham 
87381a43620SGeetha sowjanya 	if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
87481a43620SGeetha sowjanya 		ret = otx2_rss_ctx_create(pfvf, rss_context);
87581a43620SGeetha sowjanya 		if (ret)
87681a43620SGeetha sowjanya 			return ret;
87781a43620SGeetha sowjanya 	}
87881a43620SGeetha sowjanya 	if (indir) {
87981a43620SGeetha sowjanya 		rss_ctx = rss->rss_ctx[*rss_context];
88081a43620SGeetha sowjanya 		for (idx = 0; idx < rss->rss_size; idx++)
88181a43620SGeetha sowjanya 			rss_ctx->ind_tbl[idx] = indir[idx];
88281a43620SGeetha sowjanya 	}
88381a43620SGeetha sowjanya 	otx2_set_rss_table(pfvf, *rss_context);
88481a43620SGeetha sowjanya 
8856e92d71bSSunil Goutham 	return 0;
8866e92d71bSSunil Goutham }
8876e92d71bSSunil Goutham 
otx2_get_rxfh_context(struct net_device * dev,u32 * indir,u8 * hkey,u8 * hfunc,u32 rss_context)88881a43620SGeetha sowjanya static int otx2_get_rxfh_context(struct net_device *dev, u32 *indir,
88981a43620SGeetha sowjanya 				 u8 *hkey, u8 *hfunc, u32 rss_context)
89081a43620SGeetha sowjanya {
89181a43620SGeetha sowjanya 	struct otx2_nic *pfvf = netdev_priv(dev);
89281a43620SGeetha sowjanya 	struct otx2_rss_ctx *rss_ctx;
89381a43620SGeetha sowjanya 	struct otx2_rss_info *rss;
89481a43620SGeetha sowjanya 	int idx, rx_queues;
89581a43620SGeetha sowjanya 
89681a43620SGeetha sowjanya 	rss = &pfvf->hw.rss_info;
89781a43620SGeetha sowjanya 
89881a43620SGeetha sowjanya 	if (hfunc)
89981a43620SGeetha sowjanya 		*hfunc = ETH_RSS_HASH_TOP;
90081a43620SGeetha sowjanya 
90181a43620SGeetha sowjanya 	if (!indir)
90281a43620SGeetha sowjanya 		return 0;
90381a43620SGeetha sowjanya 
90481a43620SGeetha sowjanya 	if (!rss->enable && rss_context == DEFAULT_RSS_CONTEXT_GROUP) {
90581a43620SGeetha sowjanya 		rx_queues = pfvf->hw.rx_queues;
90681a43620SGeetha sowjanya 		for (idx = 0; idx < MAX_RSS_INDIR_TBL_SIZE; idx++)
90781a43620SGeetha sowjanya 			indir[idx] = ethtool_rxfh_indir_default(idx, rx_queues);
90881a43620SGeetha sowjanya 		return 0;
90981a43620SGeetha sowjanya 	}
91081a43620SGeetha sowjanya 	if (rss_context >= MAX_RSS_GROUPS)
91181a43620SGeetha sowjanya 		return -ENOENT;
91281a43620SGeetha sowjanya 
91381a43620SGeetha sowjanya 	rss_ctx = rss->rss_ctx[rss_context];
91481a43620SGeetha sowjanya 	if (!rss_ctx)
91581a43620SGeetha sowjanya 		return -ENOENT;
91681a43620SGeetha sowjanya 
91781a43620SGeetha sowjanya 	if (indir) {
91881a43620SGeetha sowjanya 		for (idx = 0; idx < rss->rss_size; idx++)
91981a43620SGeetha sowjanya 			indir[idx] = rss_ctx->ind_tbl[idx];
92081a43620SGeetha sowjanya 	}
92181a43620SGeetha sowjanya 	if (hkey)
92281a43620SGeetha sowjanya 		memcpy(hkey, rss->key, sizeof(rss->key));
92381a43620SGeetha sowjanya 
92481a43620SGeetha sowjanya 	return 0;
92581a43620SGeetha sowjanya }
92681a43620SGeetha sowjanya 
92781a43620SGeetha sowjanya /* Get RSS configuration */
otx2_get_rxfh(struct net_device * dev,u32 * indir,u8 * hkey,u8 * hfunc)92881a43620SGeetha sowjanya static int otx2_get_rxfh(struct net_device *dev, u32 *indir,
92981a43620SGeetha sowjanya 			 u8 *hkey, u8 *hfunc)
93081a43620SGeetha sowjanya {
93181a43620SGeetha sowjanya 	return otx2_get_rxfh_context(dev, indir, hkey, hfunc,
93281a43620SGeetha sowjanya 				     DEFAULT_RSS_CONTEXT_GROUP);
93381a43620SGeetha sowjanya }
93481a43620SGeetha sowjanya 
93581a43620SGeetha sowjanya /* Configure RSS table and hash key */
otx2_set_rxfh(struct net_device * dev,const u32 * indir,const u8 * hkey,const u8 hfunc)93681a43620SGeetha sowjanya static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
93781a43620SGeetha sowjanya 			 const u8 *hkey, const u8 hfunc)
93881a43620SGeetha sowjanya {
93981a43620SGeetha sowjanya 
94081a43620SGeetha sowjanya 	u32 rss_context = DEFAULT_RSS_CONTEXT_GROUP;
94181a43620SGeetha sowjanya 
94281a43620SGeetha sowjanya 	return otx2_set_rxfh_context(dev, indir, hkey, hfunc, &rss_context, 0);
94381a43620SGeetha sowjanya }
94481a43620SGeetha sowjanya 
otx2_get_msglevel(struct net_device * netdev)9456e92d71bSSunil Goutham static u32 otx2_get_msglevel(struct net_device *netdev)
9466e92d71bSSunil Goutham {
9476e92d71bSSunil Goutham 	struct otx2_nic *pfvf = netdev_priv(netdev);
9486e92d71bSSunil Goutham 
9496e92d71bSSunil Goutham 	return pfvf->msg_enable;
9506e92d71bSSunil Goutham }
9516e92d71bSSunil Goutham 
otx2_set_msglevel(struct net_device * netdev,u32 val)9526e92d71bSSunil Goutham static void otx2_set_msglevel(struct net_device *netdev, u32 val)
9536e92d71bSSunil Goutham {
9546e92d71bSSunil Goutham 	struct otx2_nic *pfvf = netdev_priv(netdev);
9556e92d71bSSunil Goutham 
9566e92d71bSSunil Goutham 	pfvf->msg_enable = val;
9576e92d71bSSunil Goutham }
9586e92d71bSSunil Goutham 
otx2_get_link(struct net_device * netdev)9596e92d71bSSunil Goutham static u32 otx2_get_link(struct net_device *netdev)
9606e92d71bSSunil Goutham {
9616e92d71bSSunil Goutham 	struct otx2_nic *pfvf = netdev_priv(netdev);
9626e92d71bSSunil Goutham 
96305c22b54STomasz Duszynski 	/* LBK link is internal and always UP */
96405c22b54STomasz Duszynski 	if (is_otx2_lbkvf(pfvf->pdev))
96505c22b54STomasz Duszynski 		return 1;
9666e92d71bSSunil Goutham 	return pfvf->linfo.link_up;
9676e92d71bSSunil Goutham }
9686e92d71bSSunil Goutham 
otx2_get_ts_info(struct net_device * netdev,struct ethtool_ts_info * info)969c9c12d33SAleksey Makarov static int otx2_get_ts_info(struct net_device *netdev,
970c9c12d33SAleksey Makarov 			    struct ethtool_ts_info *info)
971c9c12d33SAleksey Makarov {
972c9c12d33SAleksey Makarov 	struct otx2_nic *pfvf = netdev_priv(netdev);
973c9c12d33SAleksey Makarov 
974c9c12d33SAleksey Makarov 	if (!pfvf->ptp)
975c9c12d33SAleksey Makarov 		return ethtool_op_get_ts_info(netdev, info);
976c9c12d33SAleksey Makarov 
977c9c12d33SAleksey Makarov 	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
978c9c12d33SAleksey Makarov 				SOF_TIMESTAMPING_RX_SOFTWARE |
979c9c12d33SAleksey Makarov 				SOF_TIMESTAMPING_SOFTWARE |
980c9c12d33SAleksey Makarov 				SOF_TIMESTAMPING_TX_HARDWARE |
981c9c12d33SAleksey Makarov 				SOF_TIMESTAMPING_RX_HARDWARE |
982c9c12d33SAleksey Makarov 				SOF_TIMESTAMPING_RAW_HARDWARE;
983c9c12d33SAleksey Makarov 
984c9c12d33SAleksey Makarov 	info->phc_index = otx2_ptp_clock_index(pfvf);
985c9c12d33SAleksey Makarov 
9862958d17aSHariprasad Kelam 	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
9872958d17aSHariprasad Kelam 	if (test_bit(CN10K_PTP_ONESTEP, &pfvf->hw.cap_flag))
9882958d17aSHariprasad Kelam 		info->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_SYNC);
989c9c12d33SAleksey Makarov 
9902958d17aSHariprasad Kelam 	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
9912958d17aSHariprasad Kelam 			   BIT(HWTSTAMP_FILTER_ALL);
992c9c12d33SAleksey Makarov 
993c9c12d33SAleksey Makarov 	return 0;
994c9c12d33SAleksey Makarov }
995c9c12d33SAleksey Makarov 
otx2_get_fwdata(struct otx2_nic * pfvf)996d0cf9503SChristina Jacob static struct cgx_fw_data *otx2_get_fwdata(struct otx2_nic *pfvf)
997d0cf9503SChristina Jacob {
998d0cf9503SChristina Jacob 	struct cgx_fw_data *rsp = NULL;
999d0cf9503SChristina Jacob 	struct msg_req *req;
1000d0cf9503SChristina Jacob 	int err = 0;
1001d0cf9503SChristina Jacob 
1002d0cf9503SChristina Jacob 	mutex_lock(&pfvf->mbox.lock);
1003d0cf9503SChristina Jacob 	req = otx2_mbox_alloc_msg_cgx_get_aux_link_info(&pfvf->mbox);
1004d0cf9503SChristina Jacob 	if (!req) {
1005d0cf9503SChristina Jacob 		mutex_unlock(&pfvf->mbox.lock);
1006d0cf9503SChristina Jacob 		return ERR_PTR(-ENOMEM);
1007d0cf9503SChristina Jacob 	}
1008d0cf9503SChristina Jacob 
1009d0cf9503SChristina Jacob 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1010d0cf9503SChristina Jacob 	if (!err) {
1011d0cf9503SChristina Jacob 		rsp = (struct cgx_fw_data *)
1012d0cf9503SChristina Jacob 			otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr);
1013d0cf9503SChristina Jacob 	} else {
1014d0cf9503SChristina Jacob 		rsp = ERR_PTR(err);
1015d0cf9503SChristina Jacob 	}
1016d0cf9503SChristina Jacob 
1017d0cf9503SChristina Jacob 	mutex_unlock(&pfvf->mbox.lock);
1018d0cf9503SChristina Jacob 	return rsp;
1019d0cf9503SChristina Jacob }
1020d0cf9503SChristina Jacob 
otx2_get_fecparam(struct net_device * netdev,struct ethtool_fecparam * fecparam)1021d0cf9503SChristina Jacob static int otx2_get_fecparam(struct net_device *netdev,
1022d0cf9503SChristina Jacob 			     struct ethtool_fecparam *fecparam)
1023d0cf9503SChristina Jacob {
1024d0cf9503SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
1025d0cf9503SChristina Jacob 	struct cgx_fw_data *rsp;
1026d0cf9503SChristina Jacob 	const int fec[] = {
1027d0cf9503SChristina Jacob 		ETHTOOL_FEC_OFF,
1028d0cf9503SChristina Jacob 		ETHTOOL_FEC_BASER,
1029d0cf9503SChristina Jacob 		ETHTOOL_FEC_RS,
1030d0cf9503SChristina Jacob 		ETHTOOL_FEC_BASER | ETHTOOL_FEC_RS};
1031d0cf9503SChristina Jacob #define FEC_MAX_INDEX 4
1032d0cf9503SChristina Jacob 	if (pfvf->linfo.fec < FEC_MAX_INDEX)
1033d0cf9503SChristina Jacob 		fecparam->active_fec = fec[pfvf->linfo.fec];
1034d0cf9503SChristina Jacob 
1035d0cf9503SChristina Jacob 	rsp = otx2_get_fwdata(pfvf);
1036d0cf9503SChristina Jacob 	if (IS_ERR(rsp))
1037d0cf9503SChristina Jacob 		return PTR_ERR(rsp);
1038d0cf9503SChristina Jacob 
1039b0aae0bdSDavid S. Miller 	if (rsp->fwdata.supported_fec < FEC_MAX_INDEX) {
1040d0cf9503SChristina Jacob 		if (!rsp->fwdata.supported_fec)
1041d0cf9503SChristina Jacob 			fecparam->fec = ETHTOOL_FEC_NONE;
1042d0cf9503SChristina Jacob 		else
104338b5133aSDan Carpenter 			fecparam->fec = fec[rsp->fwdata.supported_fec];
1044d0cf9503SChristina Jacob 	}
1045d0cf9503SChristina Jacob 	return 0;
1046d0cf9503SChristina Jacob }
1047d0cf9503SChristina Jacob 
otx2_set_fecparam(struct net_device * netdev,struct ethtool_fecparam * fecparam)1048d0cf9503SChristina Jacob static int otx2_set_fecparam(struct net_device *netdev,
1049d0cf9503SChristina Jacob 			     struct ethtool_fecparam *fecparam)
1050d0cf9503SChristina Jacob {
1051d0cf9503SChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
1052d0cf9503SChristina Jacob 	struct mbox *mbox = &pfvf->mbox;
1053d0cf9503SChristina Jacob 	struct fec_mode *req, *rsp;
1054d0cf9503SChristina Jacob 	int err = 0, fec = 0;
1055d0cf9503SChristina Jacob 
1056d0cf9503SChristina Jacob 	switch (fecparam->fec) {
1057d0cf9503SChristina Jacob 	/* Firmware does not support AUTO mode consider it as FEC_OFF */
1058d0cf9503SChristina Jacob 	case ETHTOOL_FEC_OFF:
1059d0cf9503SChristina Jacob 	case ETHTOOL_FEC_AUTO:
1060d0cf9503SChristina Jacob 		fec = OTX2_FEC_OFF;
1061d0cf9503SChristina Jacob 		break;
1062d0cf9503SChristina Jacob 	case ETHTOOL_FEC_RS:
1063d0cf9503SChristina Jacob 		fec = OTX2_FEC_RS;
1064d0cf9503SChristina Jacob 		break;
1065d0cf9503SChristina Jacob 	case ETHTOOL_FEC_BASER:
1066d0cf9503SChristina Jacob 		fec = OTX2_FEC_BASER;
1067d0cf9503SChristina Jacob 		break;
1068d0cf9503SChristina Jacob 	default:
1069d0cf9503SChristina Jacob 		netdev_warn(pfvf->netdev, "Unsupported FEC mode: %d",
1070d0cf9503SChristina Jacob 			    fecparam->fec);
1071d0cf9503SChristina Jacob 		return -EINVAL;
1072d0cf9503SChristina Jacob 	}
1073d0cf9503SChristina Jacob 
1074d0cf9503SChristina Jacob 	if (fec == pfvf->linfo.fec)
1075d0cf9503SChristina Jacob 		return 0;
1076d0cf9503SChristina Jacob 
1077d0cf9503SChristina Jacob 	mutex_lock(&mbox->lock);
1078d0cf9503SChristina Jacob 	req = otx2_mbox_alloc_msg_cgx_set_fec_param(&pfvf->mbox);
1079d0cf9503SChristina Jacob 	if (!req) {
1080d0cf9503SChristina Jacob 		err = -ENOMEM;
1081d0cf9503SChristina Jacob 		goto end;
1082d0cf9503SChristina Jacob 	}
1083d0cf9503SChristina Jacob 	req->fec = fec;
1084d0cf9503SChristina Jacob 	err = otx2_sync_mbox_msg(&pfvf->mbox);
1085d0cf9503SChristina Jacob 	if (err)
1086d0cf9503SChristina Jacob 		goto end;
1087d0cf9503SChristina Jacob 
1088d0cf9503SChristina Jacob 	rsp = (struct fec_mode *)otx2_mbox_get_rsp(&pfvf->mbox.mbox,
1089d0cf9503SChristina Jacob 						   0, &req->hdr);
1090*c0f64fd7SDipendra Khadka 	if (IS_ERR(rsp)) {
1091*c0f64fd7SDipendra Khadka 		err = PTR_ERR(rsp);
1092*c0f64fd7SDipendra Khadka 		goto end;
1093*c0f64fd7SDipendra Khadka 	}
1094*c0f64fd7SDipendra Khadka 
1095d0cf9503SChristina Jacob 	if (rsp->fec >= 0)
1096d0cf9503SChristina Jacob 		pfvf->linfo.fec = rsp->fec;
1097d0cf9503SChristina Jacob 	else
1098d0cf9503SChristina Jacob 		err = rsp->fec;
1099d0cf9503SChristina Jacob end:
1100d0cf9503SChristina Jacob 	mutex_unlock(&mbox->lock);
1101d0cf9503SChristina Jacob 	return err;
1102d0cf9503SChristina Jacob }
1103d0cf9503SChristina Jacob 
otx2_get_fec_info(u64 index,int req_mode,struct ethtool_link_ksettings * link_ksettings)11041a50280cSChristina Jacob static void otx2_get_fec_info(u64 index, int req_mode,
11051a50280cSChristina Jacob 			      struct ethtool_link_ksettings *link_ksettings)
11061a50280cSChristina Jacob {
11071a50280cSChristina Jacob 	__ETHTOOL_DECLARE_LINK_MODE_MASK(otx2_fec_modes) = { 0, };
11081a50280cSChristina Jacob 
11091a50280cSChristina Jacob 	switch (index) {
11101a50280cSChristina Jacob 	case OTX2_FEC_NONE:
11111a50280cSChristina Jacob 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
11121a50280cSChristina Jacob 				 otx2_fec_modes);
11131a50280cSChristina Jacob 		break;
11141a50280cSChristina Jacob 	case OTX2_FEC_BASER:
11151a50280cSChristina Jacob 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
11161a50280cSChristina Jacob 				 otx2_fec_modes);
11171a50280cSChristina Jacob 		break;
11181a50280cSChristina Jacob 	case OTX2_FEC_RS:
11191a50280cSChristina Jacob 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
11201a50280cSChristina Jacob 				 otx2_fec_modes);
11211a50280cSChristina Jacob 		break;
11221a50280cSChristina Jacob 	case OTX2_FEC_BASER | OTX2_FEC_RS:
11231a50280cSChristina Jacob 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
11241a50280cSChristina Jacob 				 otx2_fec_modes);
11251a50280cSChristina Jacob 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
11261a50280cSChristina Jacob 				 otx2_fec_modes);
11271a50280cSChristina Jacob 		break;
11281a50280cSChristina Jacob 	}
11291a50280cSChristina Jacob 
11301a50280cSChristina Jacob 	/* Add fec modes to existing modes */
11311a50280cSChristina Jacob 	if (req_mode == OTX2_MODE_ADVERTISED)
11321a50280cSChristina Jacob 		linkmode_or(link_ksettings->link_modes.advertising,
11331a50280cSChristina Jacob 			    link_ksettings->link_modes.advertising,
11341a50280cSChristina Jacob 			    otx2_fec_modes);
11351a50280cSChristina Jacob 	else
11361a50280cSChristina Jacob 		linkmode_or(link_ksettings->link_modes.supported,
11371a50280cSChristina Jacob 			    link_ksettings->link_modes.supported,
11381a50280cSChristina Jacob 			    otx2_fec_modes);
11391a50280cSChristina Jacob }
11401a50280cSChristina Jacob 
otx2_get_link_mode_info(u64 link_mode_bmap,bool req_mode,struct ethtool_link_ksettings * link_ksettings)11411a50280cSChristina Jacob static void otx2_get_link_mode_info(u64 link_mode_bmap,
11421a50280cSChristina Jacob 				    bool req_mode,
11431a50280cSChristina Jacob 				    struct ethtool_link_ksettings
11441a50280cSChristina Jacob 				    *link_ksettings)
11451a50280cSChristina Jacob {
11461a50280cSChristina Jacob 	__ETHTOOL_DECLARE_LINK_MODE_MASK(otx2_link_modes) = { 0, };
11471a50280cSChristina Jacob 	const int otx2_sgmii_features[6] = {
11481a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_10baseT_Half_BIT,
11491a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_10baseT_Full_BIT,
11501a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_100baseT_Half_BIT,
11511a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_100baseT_Full_BIT,
11521a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
11531a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
11541a50280cSChristina Jacob 	};
11551a50280cSChristina Jacob 	/* CGX link modes to Ethtool link mode mapping */
11561a50280cSChristina Jacob 	const int cgx_link_mode[27] = {
11571a50280cSChristina Jacob 		0, /* SGMII  Mode */
11581a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
11591a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
11601a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
11611a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
11621a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
11631a50280cSChristina Jacob 		0,
11641a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
11651a50280cSChristina Jacob 		0,
11661a50280cSChristina Jacob 		0,
11671a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
11681a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
11691a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
11701a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
11711a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
11721a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
11731a50280cSChristina Jacob 		0,
11741a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
11751a50280cSChristina Jacob 		0,
11761a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
11771a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
11781a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
11791a50280cSChristina Jacob 		0,
11801a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
11811a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
11821a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
11831a50280cSChristina Jacob 		ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT
11841a50280cSChristina Jacob 	};
11851a50280cSChristina Jacob 	u8 bit;
11861a50280cSChristina Jacob 
11871a50280cSChristina Jacob 	for_each_set_bit(bit, (unsigned long *)&link_mode_bmap, 27) {
11881a50280cSChristina Jacob 		/* SGMII mode is set */
11891a50280cSChristina Jacob 		if (bit == 0)
11901a50280cSChristina Jacob 			linkmode_set_bit_array(otx2_sgmii_features,
11911a50280cSChristina Jacob 					       ARRAY_SIZE(otx2_sgmii_features),
11921a50280cSChristina Jacob 					       otx2_link_modes);
11931a50280cSChristina Jacob 		else
11941a50280cSChristina Jacob 			linkmode_set_bit(cgx_link_mode[bit], otx2_link_modes);
11951a50280cSChristina Jacob 	}
11961a50280cSChristina Jacob 
11971a50280cSChristina Jacob 	if (req_mode == OTX2_MODE_ADVERTISED)
11981a50280cSChristina Jacob 		linkmode_copy(link_ksettings->link_modes.advertising,
11991a50280cSChristina Jacob 			      otx2_link_modes);
12001a50280cSChristina Jacob 	else
12011a50280cSChristina Jacob 		linkmode_copy(link_ksettings->link_modes.supported,
12021a50280cSChristina Jacob 			      otx2_link_modes);
12031a50280cSChristina Jacob }
12041a50280cSChristina Jacob 
otx2_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)12051a50280cSChristina Jacob static int otx2_get_link_ksettings(struct net_device *netdev,
12061a50280cSChristina Jacob 				   struct ethtool_link_ksettings *cmd)
12071a50280cSChristina Jacob {
12081a50280cSChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
12091a50280cSChristina Jacob 	struct cgx_fw_data *rsp = NULL;
12101a50280cSChristina Jacob 
12111a50280cSChristina Jacob 	cmd->base.duplex  = pfvf->linfo.full_duplex;
12121a50280cSChristina Jacob 	cmd->base.speed   = pfvf->linfo.speed;
12131a50280cSChristina Jacob 	cmd->base.autoneg = pfvf->linfo.an;
12141a50280cSChristina Jacob 
12151a50280cSChristina Jacob 	rsp = otx2_get_fwdata(pfvf);
12161a50280cSChristina Jacob 	if (IS_ERR(rsp))
12171a50280cSChristina Jacob 		return PTR_ERR(rsp);
12181a50280cSChristina Jacob 
12191a50280cSChristina Jacob 	if (rsp->fwdata.supported_an)
12201a50280cSChristina Jacob 		ethtool_link_ksettings_add_link_mode(cmd,
12211a50280cSChristina Jacob 						     supported,
12221a50280cSChristina Jacob 						     Autoneg);
12231a50280cSChristina Jacob 
12241a50280cSChristina Jacob 	otx2_get_link_mode_info(rsp->fwdata.advertised_link_modes,
12251a50280cSChristina Jacob 				OTX2_MODE_ADVERTISED, cmd);
12261a50280cSChristina Jacob 	otx2_get_fec_info(rsp->fwdata.advertised_fec,
12271a50280cSChristina Jacob 			  OTX2_MODE_ADVERTISED, cmd);
12281a50280cSChristina Jacob 	otx2_get_link_mode_info(rsp->fwdata.supported_link_modes,
12291a50280cSChristina Jacob 				OTX2_MODE_SUPPORTED, cmd);
12301a50280cSChristina Jacob 	otx2_get_fec_info(rsp->fwdata.supported_fec,
12311a50280cSChristina Jacob 			  OTX2_MODE_SUPPORTED, cmd);
12321a50280cSChristina Jacob 	return 0;
12331a50280cSChristina Jacob }
12341a50280cSChristina Jacob 
otx2_get_advertised_mode(const struct ethtool_link_ksettings * cmd,u64 * mode)1235cff713ceSChristina Jacob static void otx2_get_advertised_mode(const struct ethtool_link_ksettings *cmd,
1236cff713ceSChristina Jacob 				     u64 *mode)
1237cff713ceSChristina Jacob {
1238cff713ceSChristina Jacob 	u32 bit_pos;
1239cff713ceSChristina Jacob 
1240cff713ceSChristina Jacob 	/* Firmware does not support requesting multiple advertised modes
1241cff713ceSChristina Jacob 	 * return first set bit
1242cff713ceSChristina Jacob 	 */
1243cff713ceSChristina Jacob 	bit_pos = find_first_bit(cmd->link_modes.advertising,
1244cff713ceSChristina Jacob 				 __ETHTOOL_LINK_MODE_MASK_NBITS);
1245cff713ceSChristina Jacob 	if (bit_pos != __ETHTOOL_LINK_MODE_MASK_NBITS)
1246cff713ceSChristina Jacob 		*mode = bit_pos;
1247cff713ceSChristina Jacob }
1248cff713ceSChristina Jacob 
otx2_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * cmd)1249cff713ceSChristina Jacob static int otx2_set_link_ksettings(struct net_device *netdev,
1250cff713ceSChristina Jacob 				   const struct ethtool_link_ksettings *cmd)
1251cff713ceSChristina Jacob {
1252cff713ceSChristina Jacob 	struct otx2_nic *pf = netdev_priv(netdev);
1253cff713ceSChristina Jacob 	struct ethtool_link_ksettings cur_ks;
1254cff713ceSChristina Jacob 	struct cgx_set_link_mode_req *req;
1255cff713ceSChristina Jacob 	struct mbox *mbox = &pf->mbox;
1256cff713ceSChristina Jacob 	int err = 0;
1257cff713ceSChristina Jacob 
1258cff713ceSChristina Jacob 	memset(&cur_ks, 0, sizeof(struct ethtool_link_ksettings));
1259cff713ceSChristina Jacob 
1260cff713ceSChristina Jacob 	if (!ethtool_validate_speed(cmd->base.speed) ||
1261cff713ceSChristina Jacob 	    !ethtool_validate_duplex(cmd->base.duplex))
1262cff713ceSChristina Jacob 		return -EINVAL;
1263cff713ceSChristina Jacob 
1264cff713ceSChristina Jacob 	if (cmd->base.autoneg != AUTONEG_ENABLE &&
1265cff713ceSChristina Jacob 	    cmd->base.autoneg != AUTONEG_DISABLE)
1266cff713ceSChristina Jacob 		return -EINVAL;
1267cff713ceSChristina Jacob 
1268cff713ceSChristina Jacob 	otx2_get_link_ksettings(netdev, &cur_ks);
1269cff713ceSChristina Jacob 
1270cff713ceSChristina Jacob 	/* Check requested modes against supported modes by hardware */
12714973056cSSean Anderson 	if (!linkmode_subset(cmd->link_modes.advertising,
12724973056cSSean Anderson 			     cur_ks.link_modes.supported))
1273cff713ceSChristina Jacob 		return -EINVAL;
1274cff713ceSChristina Jacob 
1275cff713ceSChristina Jacob 	mutex_lock(&mbox->lock);
1276cff713ceSChristina Jacob 	req = otx2_mbox_alloc_msg_cgx_set_link_mode(&pf->mbox);
1277cff713ceSChristina Jacob 	if (!req) {
1278cff713ceSChristina Jacob 		err = -ENOMEM;
1279cff713ceSChristina Jacob 		goto end;
1280cff713ceSChristina Jacob 	}
1281cff713ceSChristina Jacob 
1282cff713ceSChristina Jacob 	req->args.speed = cmd->base.speed;
1283cff713ceSChristina Jacob 	/* firmware expects 1 for half duplex and 0 for full duplex
1284cff713ceSChristina Jacob 	 * hence inverting
1285cff713ceSChristina Jacob 	 */
1286cff713ceSChristina Jacob 	req->args.duplex = cmd->base.duplex ^ 0x1;
1287cff713ceSChristina Jacob 	req->args.an = cmd->base.autoneg;
1288cff713ceSChristina Jacob 	otx2_get_advertised_mode(cmd, &req->args.mode);
1289cff713ceSChristina Jacob 
1290cff713ceSChristina Jacob 	err = otx2_sync_mbox_msg(&pf->mbox);
1291cff713ceSChristina Jacob end:
1292cff713ceSChristina Jacob 	mutex_unlock(&mbox->lock);
1293cff713ceSChristina Jacob 	return err;
1294cff713ceSChristina Jacob }
1295cff713ceSChristina Jacob 
otx2_get_fec_stats(struct net_device * netdev,struct ethtool_fec_stats * fec_stats)1296b441c4acSHariprasad Kelam static void otx2_get_fec_stats(struct net_device *netdev,
1297b441c4acSHariprasad Kelam 			       struct ethtool_fec_stats *fec_stats)
1298b441c4acSHariprasad Kelam {
1299b441c4acSHariprasad Kelam 	struct otx2_nic *pfvf = netdev_priv(netdev);
1300b441c4acSHariprasad Kelam 	struct cgx_fw_data *rsp;
1301b441c4acSHariprasad Kelam 
1302b441c4acSHariprasad Kelam 	otx2_update_lmac_fec_stats(pfvf);
1303b441c4acSHariprasad Kelam 
1304b441c4acSHariprasad Kelam 	/* Report MAC FEC stats */
1305b441c4acSHariprasad Kelam 	fec_stats->corrected_blocks.total     = pfvf->hw.cgx_fec_corr_blks;
1306b441c4acSHariprasad Kelam 	fec_stats->uncorrectable_blocks.total = pfvf->hw.cgx_fec_uncorr_blks;
1307b441c4acSHariprasad Kelam 
1308b441c4acSHariprasad Kelam 	rsp = otx2_get_fwdata(pfvf);
1309b441c4acSHariprasad Kelam 	if (!IS_ERR(rsp) && rsp->fwdata.phy.misc.has_fec_stats &&
1310b441c4acSHariprasad Kelam 	    !otx2_get_phy_fec_stats(pfvf)) {
1311b441c4acSHariprasad Kelam 		/* Fetch fwdata again because it's been recently populated with
1312b441c4acSHariprasad Kelam 		 * latest PHY FEC stats.
1313b441c4acSHariprasad Kelam 		 */
1314b441c4acSHariprasad Kelam 		rsp = otx2_get_fwdata(pfvf);
1315b441c4acSHariprasad Kelam 		if (!IS_ERR(rsp)) {
1316b441c4acSHariprasad Kelam 			struct fec_stats_s *p = &rsp->fwdata.phy.fec_stats;
1317b441c4acSHariprasad Kelam 
1318b441c4acSHariprasad Kelam 			if (pfvf->linfo.fec == OTX2_FEC_BASER) {
1319b441c4acSHariprasad Kelam 				fec_stats->corrected_blocks.total = p->brfec_corr_blks;
1320b441c4acSHariprasad Kelam 				fec_stats->uncorrectable_blocks.total = p->brfec_uncorr_blks;
1321b441c4acSHariprasad Kelam 			} else {
1322b441c4acSHariprasad Kelam 				fec_stats->corrected_blocks.total = p->rsfec_corr_cws;
1323b441c4acSHariprasad Kelam 				fec_stats->uncorrectable_blocks.total = p->rsfec_uncorr_cws;
1324b441c4acSHariprasad Kelam 			}
1325b441c4acSHariprasad Kelam 		}
1326b441c4acSHariprasad Kelam 	}
1327b441c4acSHariprasad Kelam }
1328b441c4acSHariprasad Kelam 
1329d45d8979SChristina Jacob static const struct ethtool_ops otx2_ethtool_ops = {
1330af7fcbbdSJakub Kicinski 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
13316e144b47SSuman Ghosh 				     ETHTOOL_COALESCE_MAX_FRAMES |
13326e144b47SSuman Ghosh 				     ETHTOOL_COALESCE_USE_ADAPTIVE,
133368258596SSubbaraya Sundeep 	.supported_ring_params  = ETHTOOL_RING_USE_RX_BUF_LEN |
133468258596SSubbaraya Sundeep 				  ETHTOOL_RING_USE_CQE_SIZE,
13356e92d71bSSunil Goutham 	.get_link		= otx2_get_link,
1336d45d8979SChristina Jacob 	.get_drvinfo		= otx2_get_drvinfo,
1337d45d8979SChristina Jacob 	.get_strings		= otx2_get_strings,
1338d45d8979SChristina Jacob 	.get_ethtool_stats	= otx2_get_ethtool_stats,
1339d45d8979SChristina Jacob 	.get_sset_count		= otx2_get_sset_count,
1340d45d8979SChristina Jacob 	.set_channels		= otx2_set_channels,
1341d45d8979SChristina Jacob 	.get_channels		= otx2_get_channels,
1342d45d8979SChristina Jacob 	.get_ringparam		= otx2_get_ringparam,
1343d45d8979SChristina Jacob 	.set_ringparam		= otx2_set_ringparam,
1344d45d8979SChristina Jacob 	.get_coalesce		= otx2_get_coalesce,
1345d45d8979SChristina Jacob 	.set_coalesce		= otx2_set_coalesce,
13466e92d71bSSunil Goutham 	.get_rxnfc		= otx2_get_rxnfc,
13476e92d71bSSunil Goutham 	.set_rxnfc              = otx2_set_rxnfc,
13486e92d71bSSunil Goutham 	.get_rxfh_key_size	= otx2_get_rxfh_key_size,
13496e92d71bSSunil Goutham 	.get_rxfh_indir_size	= otx2_get_rxfh_indir_size,
13506e92d71bSSunil Goutham 	.get_rxfh		= otx2_get_rxfh,
13516e92d71bSSunil Goutham 	.set_rxfh		= otx2_set_rxfh,
135281a43620SGeetha sowjanya 	.get_rxfh_context	= otx2_get_rxfh_context,
135381a43620SGeetha sowjanya 	.set_rxfh_context	= otx2_set_rxfh_context,
13546e92d71bSSunil Goutham 	.get_msglevel		= otx2_get_msglevel,
13556e92d71bSSunil Goutham 	.set_msglevel		= otx2_set_msglevel,
135675f36270SGeetha sowjanya 	.get_pauseparam		= otx2_get_pauseparam,
135775f36270SGeetha sowjanya 	.set_pauseparam		= otx2_set_pauseparam,
1358c9c12d33SAleksey Makarov 	.get_ts_info		= otx2_get_ts_info,
1359b441c4acSHariprasad Kelam 	.get_fec_stats		= otx2_get_fec_stats,
1360d0cf9503SChristina Jacob 	.get_fecparam		= otx2_get_fecparam,
1361d0cf9503SChristina Jacob 	.set_fecparam		= otx2_set_fecparam,
13621a50280cSChristina Jacob 	.get_link_ksettings     = otx2_get_link_ksettings,
1363cff713ceSChristina Jacob 	.set_link_ksettings     = otx2_set_link_ksettings,
1364d45d8979SChristina Jacob };
1365d45d8979SChristina Jacob 
otx2_set_ethtool_ops(struct net_device * netdev)1366d45d8979SChristina Jacob void otx2_set_ethtool_ops(struct net_device *netdev)
1367d45d8979SChristina Jacob {
1368d45d8979SChristina Jacob 	netdev->ethtool_ops = &otx2_ethtool_ops;
1369d45d8979SChristina Jacob }
137005c22b54STomasz Duszynski 
137105c22b54STomasz Duszynski /* VF's ethtool APIs */
otx2vf_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)137205c22b54STomasz Duszynski static void otx2vf_get_drvinfo(struct net_device *netdev,
137305c22b54STomasz Duszynski 			       struct ethtool_drvinfo *info)
137405c22b54STomasz Duszynski {
137505c22b54STomasz Duszynski 	struct otx2_nic *vf = netdev_priv(netdev);
137605c22b54STomasz Duszynski 
1377f029c781SWolfram Sang 	strscpy(info->driver, DRV_VF_NAME, sizeof(info->driver));
1378f029c781SWolfram Sang 	strscpy(info->bus_info, pci_name(vf->pdev), sizeof(info->bus_info));
137905c22b54STomasz Duszynski }
138005c22b54STomasz Duszynski 
otx2vf_get_strings(struct net_device * netdev,u32 sset,u8 * data)138105c22b54STomasz Duszynski static void otx2vf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
138205c22b54STomasz Duszynski {
138305c22b54STomasz Duszynski 	struct otx2_nic *vf = netdev_priv(netdev);
138405c22b54STomasz Duszynski 	int stats;
138505c22b54STomasz Duszynski 
138605c22b54STomasz Duszynski 	if (sset != ETH_SS_STATS)
138705c22b54STomasz Duszynski 		return;
138805c22b54STomasz Duszynski 
138905c22b54STomasz Duszynski 	for (stats = 0; stats < otx2_n_dev_stats; stats++) {
139005c22b54STomasz Duszynski 		memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN);
139105c22b54STomasz Duszynski 		data += ETH_GSTRING_LEN;
139205c22b54STomasz Duszynski 	}
139305c22b54STomasz Duszynski 
139405c22b54STomasz Duszynski 	for (stats = 0; stats < otx2_n_drv_stats; stats++) {
139505c22b54STomasz Duszynski 		memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN);
139605c22b54STomasz Duszynski 		data += ETH_GSTRING_LEN;
139705c22b54STomasz Duszynski 	}
139805c22b54STomasz Duszynski 
139905c22b54STomasz Duszynski 	otx2_get_qset_strings(vf, &data, 0);
140005c22b54STomasz Duszynski 
140105c22b54STomasz Duszynski 	strcpy(data, "reset_count");
140205c22b54STomasz Duszynski 	data += ETH_GSTRING_LEN;
140305c22b54STomasz Duszynski }
140405c22b54STomasz Duszynski 
otx2vf_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)140505c22b54STomasz Duszynski static void otx2vf_get_ethtool_stats(struct net_device *netdev,
140605c22b54STomasz Duszynski 				     struct ethtool_stats *stats, u64 *data)
140705c22b54STomasz Duszynski {
140805c22b54STomasz Duszynski 	struct otx2_nic *vf = netdev_priv(netdev);
140905c22b54STomasz Duszynski 	int stat;
141005c22b54STomasz Duszynski 
141105c22b54STomasz Duszynski 	otx2_get_dev_stats(vf);
141205c22b54STomasz Duszynski 	for (stat = 0; stat < otx2_n_dev_stats; stat++)
141305c22b54STomasz Duszynski 		*(data++) = ((u64 *)&vf->hw.dev_stats)
141405c22b54STomasz Duszynski 				[otx2_dev_stats[stat].index];
141505c22b54STomasz Duszynski 
141605c22b54STomasz Duszynski 	for (stat = 0; stat < otx2_n_drv_stats; stat++)
141705c22b54STomasz Duszynski 		*(data++) = atomic_read(&((atomic_t *)&vf->hw.drv_stats)
141805c22b54STomasz Duszynski 						[otx2_drv_stats[stat].index]);
141905c22b54STomasz Duszynski 
142005c22b54STomasz Duszynski 	otx2_get_qset_stats(vf, stats, &data);
142105c22b54STomasz Duszynski 	*(data++) = vf->reset_count;
142205c22b54STomasz Duszynski }
142305c22b54STomasz Duszynski 
otx2vf_get_sset_count(struct net_device * netdev,int sset)142405c22b54STomasz Duszynski static int otx2vf_get_sset_count(struct net_device *netdev, int sset)
142505c22b54STomasz Duszynski {
142605c22b54STomasz Duszynski 	struct otx2_nic *vf = netdev_priv(netdev);
142705c22b54STomasz Duszynski 	int qstats_count;
142805c22b54STomasz Duszynski 
142905c22b54STomasz Duszynski 	if (sset != ETH_SS_STATS)
143005c22b54STomasz Duszynski 		return -EINVAL;
143105c22b54STomasz Duszynski 
143205c22b54STomasz Duszynski 	qstats_count = otx2_n_queue_stats *
14336cebb6a4SHariprasad Kelam 		       (vf->hw.rx_queues + otx2_get_total_tx_queues(vf));
143405c22b54STomasz Duszynski 
143505c22b54STomasz Duszynski 	return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count + 1;
143605c22b54STomasz Duszynski }
143705c22b54STomasz Duszynski 
otx2vf_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)14381a50280cSChristina Jacob static int otx2vf_get_link_ksettings(struct net_device *netdev,
14391a50280cSChristina Jacob 				     struct ethtool_link_ksettings *cmd)
14401a50280cSChristina Jacob {
14411a50280cSChristina Jacob 	struct otx2_nic *pfvf = netdev_priv(netdev);
14421a50280cSChristina Jacob 
14431a50280cSChristina Jacob 	if (is_otx2_lbkvf(pfvf->pdev)) {
14441a50280cSChristina Jacob 		cmd->base.duplex = DUPLEX_FULL;
14451a50280cSChristina Jacob 		cmd->base.speed = SPEED_100000;
14461a50280cSChristina Jacob 	} else {
14471a50280cSChristina Jacob 		return otx2_get_link_ksettings(netdev, cmd);
14481a50280cSChristina Jacob 	}
14491a50280cSChristina Jacob 	return 0;
14501a50280cSChristina Jacob }
14511a50280cSChristina Jacob 
145205c22b54STomasz Duszynski static const struct ethtool_ops otx2vf_ethtool_ops = {
145305c22b54STomasz Duszynski 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
1454619c010aSSuman Ghosh 				     ETHTOOL_COALESCE_MAX_FRAMES |
1455619c010aSSuman Ghosh 				     ETHTOOL_COALESCE_USE_ADAPTIVE,
145668258596SSubbaraya Sundeep 	.supported_ring_params  = ETHTOOL_RING_USE_RX_BUF_LEN |
145768258596SSubbaraya Sundeep 				  ETHTOOL_RING_USE_CQE_SIZE,
145805c22b54STomasz Duszynski 	.get_link		= otx2_get_link,
145905c22b54STomasz Duszynski 	.get_drvinfo		= otx2vf_get_drvinfo,
146005c22b54STomasz Duszynski 	.get_strings		= otx2vf_get_strings,
146105c22b54STomasz Duszynski 	.get_ethtool_stats	= otx2vf_get_ethtool_stats,
146205c22b54STomasz Duszynski 	.get_sset_count		= otx2vf_get_sset_count,
146305c22b54STomasz Duszynski 	.set_channels		= otx2_set_channels,
146405c22b54STomasz Duszynski 	.get_channels		= otx2_get_channels,
14653cffaed2SRakesh Babu 	.get_rxnfc		= otx2_get_rxnfc,
14663cffaed2SRakesh Babu 	.set_rxnfc              = otx2_set_rxnfc,
146705c22b54STomasz Duszynski 	.get_rxfh_key_size	= otx2_get_rxfh_key_size,
146805c22b54STomasz Duszynski 	.get_rxfh_indir_size	= otx2_get_rxfh_indir_size,
146905c22b54STomasz Duszynski 	.get_rxfh		= otx2_get_rxfh,
147005c22b54STomasz Duszynski 	.set_rxfh		= otx2_set_rxfh,
147181a43620SGeetha sowjanya 	.get_rxfh_context	= otx2_get_rxfh_context,
147281a43620SGeetha sowjanya 	.set_rxfh_context	= otx2_set_rxfh_context,
147305c22b54STomasz Duszynski 	.get_ringparam		= otx2_get_ringparam,
147405c22b54STomasz Duszynski 	.set_ringparam		= otx2_set_ringparam,
147505c22b54STomasz Duszynski 	.get_coalesce		= otx2_get_coalesce,
147605c22b54STomasz Duszynski 	.set_coalesce		= otx2_set_coalesce,
147705c22b54STomasz Duszynski 	.get_msglevel		= otx2_get_msglevel,
147805c22b54STomasz Duszynski 	.set_msglevel		= otx2_set_msglevel,
147905c22b54STomasz Duszynski 	.get_pauseparam		= otx2_get_pauseparam,
148005c22b54STomasz Duszynski 	.set_pauseparam		= otx2_set_pauseparam,
14811a50280cSChristina Jacob 	.get_link_ksettings     = otx2vf_get_link_ksettings,
148243510ef4SNaveen Mamindlapalli 	.get_ts_info		= otx2_get_ts_info,
148305c22b54STomasz Duszynski };
148405c22b54STomasz Duszynski 
otx2vf_set_ethtool_ops(struct net_device * netdev)148505c22b54STomasz Duszynski void otx2vf_set_ethtool_ops(struct net_device *netdev)
148605c22b54STomasz Duszynski {
148705c22b54STomasz Duszynski 	netdev->ethtool_ops = &otx2vf_ethtool_ops;
148805c22b54STomasz Duszynski }
148905c22b54STomasz Duszynski EXPORT_SYMBOL(otx2vf_set_ethtool_ops);
1490