xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/netdevice.h>
6*4882a593Smuzhiyun #include <linux/sfp.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "ionic.h"
9*4882a593Smuzhiyun #include "ionic_bus.h"
10*4882a593Smuzhiyun #include "ionic_lif.h"
11*4882a593Smuzhiyun #include "ionic_ethtool.h"
12*4882a593Smuzhiyun #include "ionic_stats.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun static const char ionic_priv_flags_strings[][ETH_GSTRING_LEN] = {
15*4882a593Smuzhiyun #define IONIC_PRIV_F_SW_DBG_STATS	BIT(0)
16*4882a593Smuzhiyun 	"sw-dbg-stats",
17*4882a593Smuzhiyun };
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define IONIC_PRIV_FLAGS_COUNT ARRAY_SIZE(ionic_priv_flags_strings)
20*4882a593Smuzhiyun 
ionic_get_stats_strings(struct ionic_lif * lif,u8 * buf)21*4882a593Smuzhiyun static void ionic_get_stats_strings(struct ionic_lif *lif, u8 *buf)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	u32 i;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	for (i = 0; i < ionic_num_stats_grps; i++)
26*4882a593Smuzhiyun 		ionic_stats_groups[i].get_strings(lif, &buf);
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
ionic_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * buf)29*4882a593Smuzhiyun static void ionic_get_stats(struct net_device *netdev,
30*4882a593Smuzhiyun 			    struct ethtool_stats *stats, u64 *buf)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	struct ionic_lif *lif;
33*4882a593Smuzhiyun 	u32 i;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	lif = netdev_priv(netdev);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	memset(buf, 0, stats->n_stats * sizeof(*buf));
38*4882a593Smuzhiyun 	for (i = 0; i < ionic_num_stats_grps; i++)
39*4882a593Smuzhiyun 		ionic_stats_groups[i].get_values(lif, &buf);
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun 
ionic_get_stats_count(struct ionic_lif * lif)42*4882a593Smuzhiyun static int ionic_get_stats_count(struct ionic_lif *lif)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	int i, num_stats = 0;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	for (i = 0; i < ionic_num_stats_grps; i++)
47*4882a593Smuzhiyun 		num_stats += ionic_stats_groups[i].get_count(lif);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	return num_stats;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
ionic_get_sset_count(struct net_device * netdev,int sset)52*4882a593Smuzhiyun static int ionic_get_sset_count(struct net_device *netdev, int sset)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
55*4882a593Smuzhiyun 	int count = 0;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	switch (sset) {
58*4882a593Smuzhiyun 	case ETH_SS_STATS:
59*4882a593Smuzhiyun 		count = ionic_get_stats_count(lif);
60*4882a593Smuzhiyun 		break;
61*4882a593Smuzhiyun 	case ETH_SS_PRIV_FLAGS:
62*4882a593Smuzhiyun 		count = IONIC_PRIV_FLAGS_COUNT;
63*4882a593Smuzhiyun 		break;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 	return count;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
ionic_get_strings(struct net_device * netdev,u32 sset,u8 * buf)68*4882a593Smuzhiyun static void ionic_get_strings(struct net_device *netdev,
69*4882a593Smuzhiyun 			      u32 sset, u8 *buf)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	switch (sset) {
74*4882a593Smuzhiyun 	case ETH_SS_STATS:
75*4882a593Smuzhiyun 		ionic_get_stats_strings(lif, buf);
76*4882a593Smuzhiyun 		break;
77*4882a593Smuzhiyun 	case ETH_SS_PRIV_FLAGS:
78*4882a593Smuzhiyun 		memcpy(buf, ionic_priv_flags_strings,
79*4882a593Smuzhiyun 		       IONIC_PRIV_FLAGS_COUNT * ETH_GSTRING_LEN);
80*4882a593Smuzhiyun 		break;
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
ionic_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)84*4882a593Smuzhiyun static void ionic_get_drvinfo(struct net_device *netdev,
85*4882a593Smuzhiyun 			      struct ethtool_drvinfo *drvinfo)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
88*4882a593Smuzhiyun 	struct ionic *ionic = lif->ionic;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	strlcpy(drvinfo->driver, IONIC_DRV_NAME, sizeof(drvinfo->driver));
91*4882a593Smuzhiyun 	strlcpy(drvinfo->fw_version, ionic->idev.dev_info.fw_version,
92*4882a593Smuzhiyun 		sizeof(drvinfo->fw_version));
93*4882a593Smuzhiyun 	strlcpy(drvinfo->bus_info, ionic_bus_info(ionic),
94*4882a593Smuzhiyun 		sizeof(drvinfo->bus_info));
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
ionic_get_regs_len(struct net_device * netdev)97*4882a593Smuzhiyun static int ionic_get_regs_len(struct net_device *netdev)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	return (IONIC_DEV_INFO_REG_COUNT + IONIC_DEV_CMD_REG_COUNT) * sizeof(u32);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
ionic_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)102*4882a593Smuzhiyun static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
103*4882a593Smuzhiyun 			   void *p)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
106*4882a593Smuzhiyun 	unsigned int offset;
107*4882a593Smuzhiyun 	unsigned int size;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	regs->version = IONIC_DEV_CMD_REG_VERSION;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	offset = 0;
112*4882a593Smuzhiyun 	size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
113*4882a593Smuzhiyun 	memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	offset += size;
116*4882a593Smuzhiyun 	size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
117*4882a593Smuzhiyun 	memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
ionic_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * ks)120*4882a593Smuzhiyun static int ionic_get_link_ksettings(struct net_device *netdev,
121*4882a593Smuzhiyun 				    struct ethtool_link_ksettings *ks)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
124*4882a593Smuzhiyun 	struct ionic_dev *idev = &lif->ionic->idev;
125*4882a593Smuzhiyun 	int copper_seen = 0;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	ethtool_link_ksettings_zero_link_mode(ks, supported);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (!idev->port_info) {
130*4882a593Smuzhiyun 		netdev_err(netdev, "port_info not initialized\n");
131*4882a593Smuzhiyun 		return -EOPNOTSUPP;
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	/* The port_info data is found in a DMA space that the NIC keeps
135*4882a593Smuzhiyun 	 * up-to-date, so there's no need to request the data from the
136*4882a593Smuzhiyun 	 * NIC, we already have it in our memory space.
137*4882a593Smuzhiyun 	 */
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	switch (le16_to_cpu(idev->port_info->status.xcvr.pid)) {
140*4882a593Smuzhiyun 		/* Copper */
141*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_CR4:
142*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
143*4882a593Smuzhiyun 						     100000baseCR4_Full);
144*4882a593Smuzhiyun 		copper_seen++;
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_40GBASE_CR4:
147*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
148*4882a593Smuzhiyun 						     40000baseCR4_Full);
149*4882a593Smuzhiyun 		copper_seen++;
150*4882a593Smuzhiyun 		break;
151*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_25GBASE_CR_S:
152*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_25GBASE_CR_L:
153*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_25GBASE_CR_N:
154*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
155*4882a593Smuzhiyun 						     25000baseCR_Full);
156*4882a593Smuzhiyun 		copper_seen++;
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_10GBASE_AOC:
159*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_10GBASE_CU:
160*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
161*4882a593Smuzhiyun 						     10000baseCR_Full);
162*4882a593Smuzhiyun 		copper_seen++;
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 		/* Fibre */
166*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_SR4:
167*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_AOC:
168*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
169*4882a593Smuzhiyun 						     100000baseSR4_Full);
170*4882a593Smuzhiyun 		break;
171*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_CWDM4:
172*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_PSM4:
173*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_LR4:
174*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
175*4882a593Smuzhiyun 						     100000baseLR4_ER4_Full);
176*4882a593Smuzhiyun 		break;
177*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_100G_ER4:
178*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
179*4882a593Smuzhiyun 						     100000baseLR4_ER4_Full);
180*4882a593Smuzhiyun 		break;
181*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_40GBASE_SR4:
182*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_40GBASE_AOC:
183*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
184*4882a593Smuzhiyun 						     40000baseSR4_Full);
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	case IONIC_XCVR_PID_QSFP_40GBASE_LR4:
187*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
188*4882a593Smuzhiyun 						     40000baseLR4_Full);
189*4882a593Smuzhiyun 		break;
190*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_25GBASE_SR:
191*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_25GBASE_AOC:
192*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_25GBASE_ACC:
193*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
194*4882a593Smuzhiyun 						     25000baseSR_Full);
195*4882a593Smuzhiyun 		break;
196*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_10GBASE_SR:
197*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
198*4882a593Smuzhiyun 						     10000baseSR_Full);
199*4882a593Smuzhiyun 		break;
200*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_10GBASE_LR:
201*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
202*4882a593Smuzhiyun 						     10000baseLR_Full);
203*4882a593Smuzhiyun 		break;
204*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_10GBASE_LRM:
205*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
206*4882a593Smuzhiyun 						     10000baseLRM_Full);
207*4882a593Smuzhiyun 		break;
208*4882a593Smuzhiyun 	case IONIC_XCVR_PID_SFP_10GBASE_ER:
209*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported,
210*4882a593Smuzhiyun 						     10000baseER_Full);
211*4882a593Smuzhiyun 		break;
212*4882a593Smuzhiyun 	case IONIC_XCVR_PID_UNKNOWN:
213*4882a593Smuzhiyun 		/* This means there's no module plugged in */
214*4882a593Smuzhiyun 		break;
215*4882a593Smuzhiyun 	default:
216*4882a593Smuzhiyun 		dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n",
217*4882a593Smuzhiyun 			 idev->port_info->status.xcvr.pid,
218*4882a593Smuzhiyun 			 idev->port_info->status.xcvr.pid);
219*4882a593Smuzhiyun 		break;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	bitmap_copy(ks->link_modes.advertising, ks->link_modes.supported,
223*4882a593Smuzhiyun 		    __ETHTOOL_LINK_MODE_MASK_NBITS);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
226*4882a593Smuzhiyun 	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
227*4882a593Smuzhiyun 	if (idev->port_info->config.fec_type == IONIC_PORT_FEC_TYPE_FC)
228*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_BASER);
229*4882a593Smuzhiyun 	else if (idev->port_info->config.fec_type == IONIC_PORT_FEC_TYPE_RS)
230*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE);
233*4882a593Smuzhiyun 	ethtool_link_ksettings_add_link_mode(ks, supported, Pause);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	if (idev->port_info->status.xcvr.phy == IONIC_PHY_TYPE_COPPER ||
236*4882a593Smuzhiyun 	    copper_seen)
237*4882a593Smuzhiyun 		ks->base.port = PORT_DA;
238*4882a593Smuzhiyun 	else if (idev->port_info->status.xcvr.phy == IONIC_PHY_TYPE_FIBER)
239*4882a593Smuzhiyun 		ks->base.port = PORT_FIBRE;
240*4882a593Smuzhiyun 	else
241*4882a593Smuzhiyun 		ks->base.port = PORT_NONE;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (ks->base.port != PORT_NONE) {
244*4882a593Smuzhiyun 		ks->base.speed = le32_to_cpu(lif->info->status.link_speed);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 		if (le16_to_cpu(lif->info->status.link_status))
247*4882a593Smuzhiyun 			ks->base.duplex = DUPLEX_FULL;
248*4882a593Smuzhiyun 		else
249*4882a593Smuzhiyun 			ks->base.duplex = DUPLEX_UNKNOWN;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 		ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 		if (idev->port_info->config.an_enable) {
254*4882a593Smuzhiyun 			ethtool_link_ksettings_add_link_mode(ks, advertising,
255*4882a593Smuzhiyun 							     Autoneg);
256*4882a593Smuzhiyun 			ks->base.autoneg = AUTONEG_ENABLE;
257*4882a593Smuzhiyun 		}
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	return 0;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
ionic_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * ks)263*4882a593Smuzhiyun static int ionic_set_link_ksettings(struct net_device *netdev,
264*4882a593Smuzhiyun 				    const struct ethtool_link_ksettings *ks)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
267*4882a593Smuzhiyun 	struct ionic *ionic = lif->ionic;
268*4882a593Smuzhiyun 	struct ionic_dev *idev;
269*4882a593Smuzhiyun 	int err = 0;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	idev = &lif->ionic->idev;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	/* set autoneg */
274*4882a593Smuzhiyun 	if (ks->base.autoneg != idev->port_info->config.an_enable) {
275*4882a593Smuzhiyun 		mutex_lock(&ionic->dev_cmd_lock);
276*4882a593Smuzhiyun 		ionic_dev_cmd_port_autoneg(idev, ks->base.autoneg);
277*4882a593Smuzhiyun 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
278*4882a593Smuzhiyun 		mutex_unlock(&ionic->dev_cmd_lock);
279*4882a593Smuzhiyun 		if (err)
280*4882a593Smuzhiyun 			return err;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* set speed */
284*4882a593Smuzhiyun 	if (ks->base.speed != le32_to_cpu(idev->port_info->config.speed)) {
285*4882a593Smuzhiyun 		mutex_lock(&ionic->dev_cmd_lock);
286*4882a593Smuzhiyun 		ionic_dev_cmd_port_speed(idev, ks->base.speed);
287*4882a593Smuzhiyun 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
288*4882a593Smuzhiyun 		mutex_unlock(&ionic->dev_cmd_lock);
289*4882a593Smuzhiyun 		if (err)
290*4882a593Smuzhiyun 			return err;
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return 0;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
ionic_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)296*4882a593Smuzhiyun static void ionic_get_pauseparam(struct net_device *netdev,
297*4882a593Smuzhiyun 				 struct ethtool_pauseparam *pause)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
300*4882a593Smuzhiyun 	u8 pause_type;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	pause->autoneg = 0;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	pause_type = lif->ionic->idev.port_info->config.pause_type;
305*4882a593Smuzhiyun 	if (pause_type) {
306*4882a593Smuzhiyun 		pause->rx_pause = (pause_type & IONIC_PAUSE_F_RX) ? 1 : 0;
307*4882a593Smuzhiyun 		pause->tx_pause = (pause_type & IONIC_PAUSE_F_TX) ? 1 : 0;
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
ionic_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)311*4882a593Smuzhiyun static int ionic_set_pauseparam(struct net_device *netdev,
312*4882a593Smuzhiyun 				struct ethtool_pauseparam *pause)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
315*4882a593Smuzhiyun 	struct ionic *ionic = lif->ionic;
316*4882a593Smuzhiyun 	u32 requested_pause;
317*4882a593Smuzhiyun 	int err;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	if (pause->autoneg)
320*4882a593Smuzhiyun 		return -EOPNOTSUPP;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	/* change both at the same time */
323*4882a593Smuzhiyun 	requested_pause = IONIC_PORT_PAUSE_TYPE_LINK;
324*4882a593Smuzhiyun 	if (pause->rx_pause)
325*4882a593Smuzhiyun 		requested_pause |= IONIC_PAUSE_F_RX;
326*4882a593Smuzhiyun 	if (pause->tx_pause)
327*4882a593Smuzhiyun 		requested_pause |= IONIC_PAUSE_F_TX;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if (requested_pause == lif->ionic->idev.port_info->config.pause_type)
330*4882a593Smuzhiyun 		return 0;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	mutex_lock(&ionic->dev_cmd_lock);
333*4882a593Smuzhiyun 	ionic_dev_cmd_port_pause(&lif->ionic->idev, requested_pause);
334*4882a593Smuzhiyun 	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
335*4882a593Smuzhiyun 	mutex_unlock(&ionic->dev_cmd_lock);
336*4882a593Smuzhiyun 	if (err)
337*4882a593Smuzhiyun 		return err;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return 0;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
ionic_get_fecparam(struct net_device * netdev,struct ethtool_fecparam * fec)342*4882a593Smuzhiyun static int ionic_get_fecparam(struct net_device *netdev,
343*4882a593Smuzhiyun 			      struct ethtool_fecparam *fec)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	switch (lif->ionic->idev.port_info->config.fec_type) {
348*4882a593Smuzhiyun 	case IONIC_PORT_FEC_TYPE_NONE:
349*4882a593Smuzhiyun 		fec->active_fec = ETHTOOL_FEC_OFF;
350*4882a593Smuzhiyun 		break;
351*4882a593Smuzhiyun 	case IONIC_PORT_FEC_TYPE_RS:
352*4882a593Smuzhiyun 		fec->active_fec = ETHTOOL_FEC_RS;
353*4882a593Smuzhiyun 		break;
354*4882a593Smuzhiyun 	case IONIC_PORT_FEC_TYPE_FC:
355*4882a593Smuzhiyun 		fec->active_fec = ETHTOOL_FEC_BASER;
356*4882a593Smuzhiyun 		break;
357*4882a593Smuzhiyun 	}
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	fec->fec = ETHTOOL_FEC_OFF | ETHTOOL_FEC_RS | ETHTOOL_FEC_BASER;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return 0;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
ionic_set_fecparam(struct net_device * netdev,struct ethtool_fecparam * fec)364*4882a593Smuzhiyun static int ionic_set_fecparam(struct net_device *netdev,
365*4882a593Smuzhiyun 			      struct ethtool_fecparam *fec)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
368*4882a593Smuzhiyun 	u8 fec_type;
369*4882a593Smuzhiyun 	int ret = 0;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	if (lif->ionic->idev.port_info->config.an_enable) {
372*4882a593Smuzhiyun 		netdev_err(netdev, "FEC request not allowed while autoneg is enabled\n");
373*4882a593Smuzhiyun 		return -EINVAL;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	switch (fec->fec) {
377*4882a593Smuzhiyun 	case ETHTOOL_FEC_NONE:
378*4882a593Smuzhiyun 		fec_type = IONIC_PORT_FEC_TYPE_NONE;
379*4882a593Smuzhiyun 		break;
380*4882a593Smuzhiyun 	case ETHTOOL_FEC_OFF:
381*4882a593Smuzhiyun 		fec_type = IONIC_PORT_FEC_TYPE_NONE;
382*4882a593Smuzhiyun 		break;
383*4882a593Smuzhiyun 	case ETHTOOL_FEC_RS:
384*4882a593Smuzhiyun 		fec_type = IONIC_PORT_FEC_TYPE_RS;
385*4882a593Smuzhiyun 		break;
386*4882a593Smuzhiyun 	case ETHTOOL_FEC_BASER:
387*4882a593Smuzhiyun 		fec_type = IONIC_PORT_FEC_TYPE_FC;
388*4882a593Smuzhiyun 		break;
389*4882a593Smuzhiyun 	case ETHTOOL_FEC_AUTO:
390*4882a593Smuzhiyun 	default:
391*4882a593Smuzhiyun 		netdev_err(netdev, "FEC request 0x%04x not supported\n",
392*4882a593Smuzhiyun 			   fec->fec);
393*4882a593Smuzhiyun 		return -EINVAL;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (fec_type != lif->ionic->idev.port_info->config.fec_type) {
397*4882a593Smuzhiyun 		mutex_lock(&lif->ionic->dev_cmd_lock);
398*4882a593Smuzhiyun 		ionic_dev_cmd_port_fec(&lif->ionic->idev, fec_type);
399*4882a593Smuzhiyun 		ret = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
400*4882a593Smuzhiyun 		mutex_unlock(&lif->ionic->dev_cmd_lock);
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	return ret;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
ionic_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * coalesce)406*4882a593Smuzhiyun static int ionic_get_coalesce(struct net_device *netdev,
407*4882a593Smuzhiyun 			      struct ethtool_coalesce *coalesce)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	coalesce->tx_coalesce_usecs = lif->tx_coalesce_usecs;
412*4882a593Smuzhiyun 	coalesce->rx_coalesce_usecs = lif->rx_coalesce_usecs;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
415*4882a593Smuzhiyun 		coalesce->use_adaptive_tx_coalesce = test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
416*4882a593Smuzhiyun 	else
417*4882a593Smuzhiyun 		coalesce->use_adaptive_tx_coalesce = 0;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	coalesce->use_adaptive_rx_coalesce = test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	return 0;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
ionic_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * coalesce)424*4882a593Smuzhiyun static int ionic_set_coalesce(struct net_device *netdev,
425*4882a593Smuzhiyun 			      struct ethtool_coalesce *coalesce)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
428*4882a593Smuzhiyun 	struct ionic_identity *ident;
429*4882a593Smuzhiyun 	u32 rx_coal, rx_dim;
430*4882a593Smuzhiyun 	u32 tx_coal, tx_dim;
431*4882a593Smuzhiyun 	unsigned int i;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	ident = &lif->ionic->ident;
434*4882a593Smuzhiyun 	if (ident->dev.intr_coal_div == 0) {
435*4882a593Smuzhiyun 		netdev_warn(netdev, "bad HW value in dev.intr_coal_div = %d\n",
436*4882a593Smuzhiyun 			    ident->dev.intr_coal_div);
437*4882a593Smuzhiyun 		return -EIO;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/* Tx normally shares Rx interrupt, so only change Rx if not split */
441*4882a593Smuzhiyun 	if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) &&
442*4882a593Smuzhiyun 	    (coalesce->tx_coalesce_usecs != lif->rx_coalesce_usecs ||
443*4882a593Smuzhiyun 	     coalesce->use_adaptive_tx_coalesce)) {
444*4882a593Smuzhiyun 		netdev_warn(netdev, "only rx parameters can be changed\n");
445*4882a593Smuzhiyun 		return -EINVAL;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	/* Convert the usec request to a HW usable value.  If they asked
449*4882a593Smuzhiyun 	 * for non-zero and it resolved to zero, bump it up
450*4882a593Smuzhiyun 	 */
451*4882a593Smuzhiyun 	rx_coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->rx_coalesce_usecs);
452*4882a593Smuzhiyun 	if (!rx_coal && coalesce->rx_coalesce_usecs)
453*4882a593Smuzhiyun 		rx_coal = 1;
454*4882a593Smuzhiyun 	tx_coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->tx_coalesce_usecs);
455*4882a593Smuzhiyun 	if (!tx_coal && coalesce->tx_coalesce_usecs)
456*4882a593Smuzhiyun 		tx_coal = 1;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	if (rx_coal > IONIC_INTR_CTRL_COAL_MAX ||
459*4882a593Smuzhiyun 	    tx_coal > IONIC_INTR_CTRL_COAL_MAX)
460*4882a593Smuzhiyun 		return -ERANGE;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	/* Save the new values */
463*4882a593Smuzhiyun 	lif->rx_coalesce_usecs = coalesce->rx_coalesce_usecs;
464*4882a593Smuzhiyun 	lif->rx_coalesce_hw = rx_coal;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
467*4882a593Smuzhiyun 		lif->tx_coalesce_usecs = coalesce->tx_coalesce_usecs;
468*4882a593Smuzhiyun 	else
469*4882a593Smuzhiyun 		lif->tx_coalesce_usecs = coalesce->rx_coalesce_usecs;
470*4882a593Smuzhiyun 	lif->tx_coalesce_hw = tx_coal;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	if (coalesce->use_adaptive_rx_coalesce) {
473*4882a593Smuzhiyun 		set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
474*4882a593Smuzhiyun 		rx_dim = rx_coal;
475*4882a593Smuzhiyun 	} else {
476*4882a593Smuzhiyun 		clear_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
477*4882a593Smuzhiyun 		rx_dim = 0;
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	if (coalesce->use_adaptive_tx_coalesce) {
481*4882a593Smuzhiyun 		set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
482*4882a593Smuzhiyun 		tx_dim = tx_coal;
483*4882a593Smuzhiyun 	} else {
484*4882a593Smuzhiyun 		clear_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
485*4882a593Smuzhiyun 		tx_dim = 0;
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
489*4882a593Smuzhiyun 		for (i = 0; i < lif->nxqs; i++) {
490*4882a593Smuzhiyun 			if (lif->rxqcqs[i]->flags & IONIC_QCQ_F_INTR) {
491*4882a593Smuzhiyun 				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
492*4882a593Smuzhiyun 						     lif->rxqcqs[i]->intr.index,
493*4882a593Smuzhiyun 						     lif->rx_coalesce_hw);
494*4882a593Smuzhiyun 				lif->rxqcqs[i]->intr.dim_coal_hw = rx_dim;
495*4882a593Smuzhiyun 			}
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 			if (lif->txqcqs[i]->flags & IONIC_QCQ_F_INTR) {
498*4882a593Smuzhiyun 				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
499*4882a593Smuzhiyun 						     lif->txqcqs[i]->intr.index,
500*4882a593Smuzhiyun 						     lif->tx_coalesce_hw);
501*4882a593Smuzhiyun 				lif->txqcqs[i]->intr.dim_coal_hw = tx_dim;
502*4882a593Smuzhiyun 			}
503*4882a593Smuzhiyun 		}
504*4882a593Smuzhiyun 	}
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	return 0;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
ionic_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring)509*4882a593Smuzhiyun static void ionic_get_ringparam(struct net_device *netdev,
510*4882a593Smuzhiyun 				struct ethtool_ringparam *ring)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	ring->tx_max_pending = IONIC_MAX_TX_DESC;
515*4882a593Smuzhiyun 	ring->tx_pending = lif->ntxq_descs;
516*4882a593Smuzhiyun 	ring->rx_max_pending = IONIC_MAX_RX_DESC;
517*4882a593Smuzhiyun 	ring->rx_pending = lif->nrxq_descs;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun 
ionic_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring)520*4882a593Smuzhiyun static int ionic_set_ringparam(struct net_device *netdev,
521*4882a593Smuzhiyun 			       struct ethtool_ringparam *ring)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
524*4882a593Smuzhiyun 	struct ionic_queue_params qparam;
525*4882a593Smuzhiyun 	int err;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	ionic_init_queue_params(lif, &qparam);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
530*4882a593Smuzhiyun 		netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n");
531*4882a593Smuzhiyun 		return -EINVAL;
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	if (!is_power_of_2(ring->tx_pending) ||
535*4882a593Smuzhiyun 	    !is_power_of_2(ring->rx_pending)) {
536*4882a593Smuzhiyun 		netdev_info(netdev, "Descriptor count must be a power of 2\n");
537*4882a593Smuzhiyun 		return -EINVAL;
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	/* if nothing to do return success */
541*4882a593Smuzhiyun 	if (ring->tx_pending == lif->ntxq_descs &&
542*4882a593Smuzhiyun 	    ring->rx_pending == lif->nrxq_descs)
543*4882a593Smuzhiyun 		return 0;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	if (ring->tx_pending != lif->ntxq_descs)
546*4882a593Smuzhiyun 		netdev_info(netdev, "Changing Tx ring size from %d to %d\n",
547*4882a593Smuzhiyun 			    lif->ntxq_descs, ring->tx_pending);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (ring->rx_pending != lif->nrxq_descs)
550*4882a593Smuzhiyun 		netdev_info(netdev, "Changing Rx ring size from %d to %d\n",
551*4882a593Smuzhiyun 			    lif->nrxq_descs, ring->rx_pending);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	/* if we're not running, just set the values and return */
554*4882a593Smuzhiyun 	if (!netif_running(lif->netdev)) {
555*4882a593Smuzhiyun 		lif->ntxq_descs = ring->tx_pending;
556*4882a593Smuzhiyun 		lif->nrxq_descs = ring->rx_pending;
557*4882a593Smuzhiyun 		return 0;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	qparam.ntxq_descs = ring->tx_pending;
561*4882a593Smuzhiyun 	qparam.nrxq_descs = ring->rx_pending;
562*4882a593Smuzhiyun 	err = ionic_reconfigure_queues(lif, &qparam);
563*4882a593Smuzhiyun 	if (err)
564*4882a593Smuzhiyun 		netdev_info(netdev, "Ring reconfiguration failed, changes canceled: %d\n", err);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	return err;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
ionic_get_channels(struct net_device * netdev,struct ethtool_channels * ch)569*4882a593Smuzhiyun static void ionic_get_channels(struct net_device *netdev,
570*4882a593Smuzhiyun 			       struct ethtool_channels *ch)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	/* report maximum channels */
575*4882a593Smuzhiyun 	ch->max_combined = lif->ionic->ntxqs_per_lif;
576*4882a593Smuzhiyun 	ch->max_rx = lif->ionic->ntxqs_per_lif / 2;
577*4882a593Smuzhiyun 	ch->max_tx = lif->ionic->ntxqs_per_lif / 2;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* report current channels */
580*4882a593Smuzhiyun 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
581*4882a593Smuzhiyun 		ch->rx_count = lif->nxqs;
582*4882a593Smuzhiyun 		ch->tx_count = lif->nxqs;
583*4882a593Smuzhiyun 	} else {
584*4882a593Smuzhiyun 		ch->combined_count = lif->nxqs;
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
ionic_set_channels(struct net_device * netdev,struct ethtool_channels * ch)588*4882a593Smuzhiyun static int ionic_set_channels(struct net_device *netdev,
589*4882a593Smuzhiyun 			      struct ethtool_channels *ch)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
592*4882a593Smuzhiyun 	struct ionic_queue_params qparam;
593*4882a593Smuzhiyun 	int max_cnt;
594*4882a593Smuzhiyun 	int err;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	ionic_init_queue_params(lif, &qparam);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (ch->rx_count != ch->tx_count) {
599*4882a593Smuzhiyun 		netdev_info(netdev, "The rx and tx count must be equal\n");
600*4882a593Smuzhiyun 		return -EINVAL;
601*4882a593Smuzhiyun 	}
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	if (ch->combined_count && ch->rx_count) {
604*4882a593Smuzhiyun 		netdev_info(netdev, "Use either combined or rx and tx, not both\n");
605*4882a593Smuzhiyun 		return -EINVAL;
606*4882a593Smuzhiyun 	}
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	max_cnt = lif->ionic->ntxqs_per_lif;
609*4882a593Smuzhiyun 	if (ch->combined_count) {
610*4882a593Smuzhiyun 		if (ch->combined_count > max_cnt)
611*4882a593Smuzhiyun 			return -EINVAL;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 		if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
614*4882a593Smuzhiyun 			netdev_info(lif->netdev, "Sharing queue interrupts\n");
615*4882a593Smuzhiyun 		else if (ch->combined_count == lif->nxqs)
616*4882a593Smuzhiyun 			return 0;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 		if (lif->nxqs != ch->combined_count)
619*4882a593Smuzhiyun 			netdev_info(netdev, "Changing queue count from %d to %d\n",
620*4882a593Smuzhiyun 				    lif->nxqs, ch->combined_count);
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 		qparam.nxqs = ch->combined_count;
623*4882a593Smuzhiyun 		qparam.intr_split = 0;
624*4882a593Smuzhiyun 	} else {
625*4882a593Smuzhiyun 		max_cnt /= 2;
626*4882a593Smuzhiyun 		if (ch->rx_count > max_cnt)
627*4882a593Smuzhiyun 			return -EINVAL;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 		if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
630*4882a593Smuzhiyun 			netdev_info(lif->netdev, "Splitting queue interrupts\n");
631*4882a593Smuzhiyun 		else if (ch->rx_count == lif->nxqs)
632*4882a593Smuzhiyun 			return 0;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 		if (lif->nxqs != ch->rx_count)
635*4882a593Smuzhiyun 			netdev_info(netdev, "Changing queue count from %d to %d\n",
636*4882a593Smuzhiyun 				    lif->nxqs, ch->rx_count);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 		qparam.nxqs = ch->rx_count;
639*4882a593Smuzhiyun 		qparam.intr_split = 1;
640*4882a593Smuzhiyun 	}
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	/* if we're not running, just set the values and return */
643*4882a593Smuzhiyun 	if (!netif_running(lif->netdev)) {
644*4882a593Smuzhiyun 		lif->nxqs = qparam.nxqs;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 		if (qparam.intr_split) {
647*4882a593Smuzhiyun 			set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
648*4882a593Smuzhiyun 		} else {
649*4882a593Smuzhiyun 			clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
650*4882a593Smuzhiyun 			lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
651*4882a593Smuzhiyun 			lif->tx_coalesce_hw = lif->rx_coalesce_hw;
652*4882a593Smuzhiyun 		}
653*4882a593Smuzhiyun 		return 0;
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	err = ionic_reconfigure_queues(lif, &qparam);
657*4882a593Smuzhiyun 	if (err)
658*4882a593Smuzhiyun 		netdev_info(netdev, "Queue reconfiguration failed, changes canceled: %d\n", err);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	return err;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
ionic_get_priv_flags(struct net_device * netdev)663*4882a593Smuzhiyun static u32 ionic_get_priv_flags(struct net_device *netdev)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
666*4882a593Smuzhiyun 	u32 priv_flags = 0;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	if (test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state))
669*4882a593Smuzhiyun 		priv_flags |= IONIC_PRIV_F_SW_DBG_STATS;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	return priv_flags;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
ionic_set_priv_flags(struct net_device * netdev,u32 priv_flags)674*4882a593Smuzhiyun static int ionic_set_priv_flags(struct net_device *netdev, u32 priv_flags)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	clear_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state);
679*4882a593Smuzhiyun 	if (priv_flags & IONIC_PRIV_F_SW_DBG_STATS)
680*4882a593Smuzhiyun 		set_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state);
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	return 0;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
ionic_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * info,u32 * rules)685*4882a593Smuzhiyun static int ionic_get_rxnfc(struct net_device *netdev,
686*4882a593Smuzhiyun 			   struct ethtool_rxnfc *info, u32 *rules)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
689*4882a593Smuzhiyun 	int err = 0;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	switch (info->cmd) {
692*4882a593Smuzhiyun 	case ETHTOOL_GRXRINGS:
693*4882a593Smuzhiyun 		info->data = lif->nxqs;
694*4882a593Smuzhiyun 		break;
695*4882a593Smuzhiyun 	default:
696*4882a593Smuzhiyun 		netdev_err(netdev, "Command parameter %d is not supported\n",
697*4882a593Smuzhiyun 			   info->cmd);
698*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	return err;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
ionic_get_rxfh_indir_size(struct net_device * netdev)704*4882a593Smuzhiyun static u32 ionic_get_rxfh_indir_size(struct net_device *netdev)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	return le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
ionic_get_rxfh_key_size(struct net_device * netdev)711*4882a593Smuzhiyun static u32 ionic_get_rxfh_key_size(struct net_device *netdev)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	return IONIC_RSS_HASH_KEY_SIZE;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun 
ionic_get_rxfh(struct net_device * netdev,u32 * indir,u8 * key,u8 * hfunc)716*4882a593Smuzhiyun static int ionic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
717*4882a593Smuzhiyun 			  u8 *hfunc)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
720*4882a593Smuzhiyun 	unsigned int i, tbl_sz;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	if (indir) {
723*4882a593Smuzhiyun 		tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
724*4882a593Smuzhiyun 		for (i = 0; i < tbl_sz; i++)
725*4882a593Smuzhiyun 			indir[i] = lif->rss_ind_tbl[i];
726*4882a593Smuzhiyun 	}
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	if (key)
729*4882a593Smuzhiyun 		memcpy(key, lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (hfunc)
732*4882a593Smuzhiyun 		*hfunc = ETH_RSS_HASH_TOP;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
ionic_set_rxfh(struct net_device * netdev,const u32 * indir,const u8 * key,const u8 hfunc)737*4882a593Smuzhiyun static int ionic_set_rxfh(struct net_device *netdev, const u32 *indir,
738*4882a593Smuzhiyun 			  const u8 *key, const u8 hfunc)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
741*4882a593Smuzhiyun 	int err;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
744*4882a593Smuzhiyun 		return -EOPNOTSUPP;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	err = ionic_lif_rss_config(lif, lif->rss_types, key, indir);
747*4882a593Smuzhiyun 	if (err)
748*4882a593Smuzhiyun 		return err;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	return 0;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun 
ionic_set_tunable(struct net_device * dev,const struct ethtool_tunable * tuna,const void * data)753*4882a593Smuzhiyun static int ionic_set_tunable(struct net_device *dev,
754*4882a593Smuzhiyun 			     const struct ethtool_tunable *tuna,
755*4882a593Smuzhiyun 			     const void *data)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(dev);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	switch (tuna->id) {
760*4882a593Smuzhiyun 	case ETHTOOL_RX_COPYBREAK:
761*4882a593Smuzhiyun 		lif->rx_copybreak = *(u32 *)data;
762*4882a593Smuzhiyun 		break;
763*4882a593Smuzhiyun 	default:
764*4882a593Smuzhiyun 		return -EOPNOTSUPP;
765*4882a593Smuzhiyun 	}
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	return 0;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
ionic_get_tunable(struct net_device * netdev,const struct ethtool_tunable * tuna,void * data)770*4882a593Smuzhiyun static int ionic_get_tunable(struct net_device *netdev,
771*4882a593Smuzhiyun 			     const struct ethtool_tunable *tuna, void *data)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	switch (tuna->id) {
776*4882a593Smuzhiyun 	case ETHTOOL_RX_COPYBREAK:
777*4882a593Smuzhiyun 		*(u32 *)data = lif->rx_copybreak;
778*4882a593Smuzhiyun 		break;
779*4882a593Smuzhiyun 	default:
780*4882a593Smuzhiyun 		return -EOPNOTSUPP;
781*4882a593Smuzhiyun 	}
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	return 0;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
ionic_get_module_info(struct net_device * netdev,struct ethtool_modinfo * modinfo)786*4882a593Smuzhiyun static int ionic_get_module_info(struct net_device *netdev,
787*4882a593Smuzhiyun 				 struct ethtool_modinfo *modinfo)
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
791*4882a593Smuzhiyun 	struct ionic_dev *idev = &lif->ionic->idev;
792*4882a593Smuzhiyun 	struct ionic_xcvr_status *xcvr;
793*4882a593Smuzhiyun 	struct sfp_eeprom_base *sfp;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	xcvr = &idev->port_info->status.xcvr;
796*4882a593Smuzhiyun 	sfp = (struct sfp_eeprom_base *) xcvr->sprom;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	/* report the module data type and length */
799*4882a593Smuzhiyun 	switch (sfp->phys_id) {
800*4882a593Smuzhiyun 	case SFF8024_ID_SFP:
801*4882a593Smuzhiyun 		modinfo->type = ETH_MODULE_SFF_8079;
802*4882a593Smuzhiyun 		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
803*4882a593Smuzhiyun 		break;
804*4882a593Smuzhiyun 	case SFF8024_ID_QSFP_8436_8636:
805*4882a593Smuzhiyun 	case SFF8024_ID_QSFP28_8636:
806*4882a593Smuzhiyun 		modinfo->type = ETH_MODULE_SFF_8436;
807*4882a593Smuzhiyun 		modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
808*4882a593Smuzhiyun 		break;
809*4882a593Smuzhiyun 	default:
810*4882a593Smuzhiyun 		netdev_info(netdev, "unknown xcvr type 0x%02x\n",
811*4882a593Smuzhiyun 			    xcvr->sprom[0]);
812*4882a593Smuzhiyun 		modinfo->type = 0;
813*4882a593Smuzhiyun 		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
814*4882a593Smuzhiyun 		break;
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	return 0;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun 
ionic_get_module_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)820*4882a593Smuzhiyun static int ionic_get_module_eeprom(struct net_device *netdev,
821*4882a593Smuzhiyun 				   struct ethtool_eeprom *ee,
822*4882a593Smuzhiyun 				   u8 *data)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
825*4882a593Smuzhiyun 	struct ionic_dev *idev = &lif->ionic->idev;
826*4882a593Smuzhiyun 	struct ionic_xcvr_status *xcvr;
827*4882a593Smuzhiyun 	char tbuf[sizeof(xcvr->sprom)];
828*4882a593Smuzhiyun 	int count = 10;
829*4882a593Smuzhiyun 	u32 len;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	/* The NIC keeps the module prom up-to-date in the DMA space
832*4882a593Smuzhiyun 	 * so we can simply copy the module bytes into the data buffer.
833*4882a593Smuzhiyun 	 */
834*4882a593Smuzhiyun 	xcvr = &idev->port_info->status.xcvr;
835*4882a593Smuzhiyun 	len = min_t(u32, sizeof(xcvr->sprom), ee->len);
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	do {
838*4882a593Smuzhiyun 		memcpy(data, xcvr->sprom, len);
839*4882a593Smuzhiyun 		memcpy(tbuf, xcvr->sprom, len);
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 		/* Let's make sure we got a consistent copy */
842*4882a593Smuzhiyun 		if (!memcmp(data, tbuf, len))
843*4882a593Smuzhiyun 			break;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	} while (--count);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	if (!count)
848*4882a593Smuzhiyun 		return -ETIMEDOUT;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
ionic_nway_reset(struct net_device * netdev)853*4882a593Smuzhiyun static int ionic_nway_reset(struct net_device *netdev)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 	struct ionic_lif *lif = netdev_priv(netdev);
856*4882a593Smuzhiyun 	struct ionic *ionic = lif->ionic;
857*4882a593Smuzhiyun 	int err = 0;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	/* flap the link to force auto-negotiation */
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	mutex_lock(&ionic->dev_cmd_lock);
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_DOWN);
864*4882a593Smuzhiyun 	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	if (!err) {
867*4882a593Smuzhiyun 		ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP);
868*4882a593Smuzhiyun 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
869*4882a593Smuzhiyun 	}
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	mutex_unlock(&ionic->dev_cmd_lock);
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	return err;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun static const struct ethtool_ops ionic_ethtool_ops = {
877*4882a593Smuzhiyun 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
878*4882a593Smuzhiyun 				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
879*4882a593Smuzhiyun 				     ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
880*4882a593Smuzhiyun 	.get_drvinfo		= ionic_get_drvinfo,
881*4882a593Smuzhiyun 	.get_regs_len		= ionic_get_regs_len,
882*4882a593Smuzhiyun 	.get_regs		= ionic_get_regs,
883*4882a593Smuzhiyun 	.get_link		= ethtool_op_get_link,
884*4882a593Smuzhiyun 	.get_link_ksettings	= ionic_get_link_ksettings,
885*4882a593Smuzhiyun 	.set_link_ksettings	= ionic_set_link_ksettings,
886*4882a593Smuzhiyun 	.get_coalesce		= ionic_get_coalesce,
887*4882a593Smuzhiyun 	.set_coalesce		= ionic_set_coalesce,
888*4882a593Smuzhiyun 	.get_ringparam		= ionic_get_ringparam,
889*4882a593Smuzhiyun 	.set_ringparam		= ionic_set_ringparam,
890*4882a593Smuzhiyun 	.get_channels		= ionic_get_channels,
891*4882a593Smuzhiyun 	.set_channels		= ionic_set_channels,
892*4882a593Smuzhiyun 	.get_strings		= ionic_get_strings,
893*4882a593Smuzhiyun 	.get_ethtool_stats	= ionic_get_stats,
894*4882a593Smuzhiyun 	.get_sset_count		= ionic_get_sset_count,
895*4882a593Smuzhiyun 	.get_priv_flags		= ionic_get_priv_flags,
896*4882a593Smuzhiyun 	.set_priv_flags		= ionic_set_priv_flags,
897*4882a593Smuzhiyun 	.get_rxnfc		= ionic_get_rxnfc,
898*4882a593Smuzhiyun 	.get_rxfh_indir_size	= ionic_get_rxfh_indir_size,
899*4882a593Smuzhiyun 	.get_rxfh_key_size	= ionic_get_rxfh_key_size,
900*4882a593Smuzhiyun 	.get_rxfh		= ionic_get_rxfh,
901*4882a593Smuzhiyun 	.set_rxfh		= ionic_set_rxfh,
902*4882a593Smuzhiyun 	.get_tunable		= ionic_get_tunable,
903*4882a593Smuzhiyun 	.set_tunable		= ionic_set_tunable,
904*4882a593Smuzhiyun 	.get_module_info	= ionic_get_module_info,
905*4882a593Smuzhiyun 	.get_module_eeprom	= ionic_get_module_eeprom,
906*4882a593Smuzhiyun 	.get_pauseparam		= ionic_get_pauseparam,
907*4882a593Smuzhiyun 	.set_pauseparam		= ionic_set_pauseparam,
908*4882a593Smuzhiyun 	.get_fecparam		= ionic_get_fecparam,
909*4882a593Smuzhiyun 	.set_fecparam		= ionic_set_fecparam,
910*4882a593Smuzhiyun 	.nway_reset		= ionic_nway_reset,
911*4882a593Smuzhiyun };
912*4882a593Smuzhiyun 
ionic_ethtool_set_ops(struct net_device * netdev)913*4882a593Smuzhiyun void ionic_ethtool_set_ops(struct net_device *netdev)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun 	netdev->ethtool_ops = &ionic_ethtool_ops;
916*4882a593Smuzhiyun }
917