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