xref: /openbmc/linux/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c (revision 55e43d6abd078ed6d219902ce8cb4d68e3c993ba)
14d03e00aSShannon Nelson // SPDX-License-Identifier: GPL-2.0
24d03e00aSShannon Nelson /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
34d03e00aSShannon Nelson 
44d03e00aSShannon Nelson #include <linux/module.h>
54d03e00aSShannon Nelson #include <linux/netdevice.h>
6840eef59SShannon Nelson #include <linux/sfp.h>
74d03e00aSShannon Nelson 
84d03e00aSShannon Nelson #include "ionic.h"
94d03e00aSShannon Nelson #include "ionic_bus.h"
104d03e00aSShannon Nelson #include "ionic_lif.h"
114d03e00aSShannon Nelson #include "ionic_ethtool.h"
12e470355bSShannon Nelson #include "ionic_stats.h"
13e470355bSShannon Nelson 
ionic_get_stats_strings(struct ionic_lif * lif,u8 * buf)14e470355bSShannon Nelson static void ionic_get_stats_strings(struct ionic_lif *lif, u8 *buf)
15e470355bSShannon Nelson {
16e470355bSShannon Nelson 	u32 i;
17e470355bSShannon Nelson 
18e470355bSShannon Nelson 	for (i = 0; i < ionic_num_stats_grps; i++)
19e470355bSShannon Nelson 		ionic_stats_groups[i].get_strings(lif, &buf);
20e470355bSShannon Nelson }
21e470355bSShannon Nelson 
ionic_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * buf)22e470355bSShannon Nelson static void ionic_get_stats(struct net_device *netdev,
23e470355bSShannon Nelson 			    struct ethtool_stats *stats, u64 *buf)
24e470355bSShannon Nelson {
2525cc5a5fSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
26e470355bSShannon Nelson 	u32 i;
27e470355bSShannon Nelson 
28f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
29f5123686SShannon Nelson 		return;
30f5123686SShannon Nelson 
31e470355bSShannon Nelson 	memset(buf, 0, stats->n_stats * sizeof(*buf));
32e470355bSShannon Nelson 	for (i = 0; i < ionic_num_stats_grps; i++)
33e470355bSShannon Nelson 		ionic_stats_groups[i].get_values(lif, &buf);
34e470355bSShannon Nelson }
35e470355bSShannon Nelson 
ionic_get_stats_count(struct ionic_lif * lif)36e470355bSShannon Nelson static int ionic_get_stats_count(struct ionic_lif *lif)
37e470355bSShannon Nelson {
38e470355bSShannon Nelson 	int i, num_stats = 0;
39e470355bSShannon Nelson 
40e470355bSShannon Nelson 	for (i = 0; i < ionic_num_stats_grps; i++)
41e470355bSShannon Nelson 		num_stats += ionic_stats_groups[i].get_count(lif);
42e470355bSShannon Nelson 
43e470355bSShannon Nelson 	return num_stats;
44e470355bSShannon Nelson }
45e470355bSShannon Nelson 
ionic_get_sset_count(struct net_device * netdev,int sset)46e470355bSShannon Nelson static int ionic_get_sset_count(struct net_device *netdev, int sset)
47e470355bSShannon Nelson {
48e470355bSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
49e470355bSShannon Nelson 	int count = 0;
50e470355bSShannon Nelson 
51e470355bSShannon Nelson 	switch (sset) {
52e470355bSShannon Nelson 	case ETH_SS_STATS:
53e470355bSShannon Nelson 		count = ionic_get_stats_count(lif);
54e470355bSShannon Nelson 		break;
55e470355bSShannon Nelson 	}
56e470355bSShannon Nelson 	return count;
57e470355bSShannon Nelson }
58e470355bSShannon Nelson 
ionic_get_strings(struct net_device * netdev,u32 sset,u8 * buf)59e470355bSShannon Nelson static void ionic_get_strings(struct net_device *netdev,
60e470355bSShannon Nelson 			      u32 sset, u8 *buf)
61e470355bSShannon Nelson {
62e470355bSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
63e470355bSShannon Nelson 
64e470355bSShannon Nelson 	switch (sset) {
65e470355bSShannon Nelson 	case ETH_SS_STATS:
66e470355bSShannon Nelson 		ionic_get_stats_strings(lif, buf);
67e470355bSShannon Nelson 		break;
68e470355bSShannon Nelson 	}
69e470355bSShannon Nelson }
704d03e00aSShannon Nelson 
ionic_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)714d03e00aSShannon Nelson static void ionic_get_drvinfo(struct net_device *netdev,
724d03e00aSShannon Nelson 			      struct ethtool_drvinfo *drvinfo)
734d03e00aSShannon Nelson {
744d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
754d03e00aSShannon Nelson 	struct ionic *ionic = lif->ionic;
764d03e00aSShannon Nelson 
77799c230eSShannon Nelson 	strscpy(drvinfo->driver, IONIC_DRV_NAME, sizeof(drvinfo->driver));
78799c230eSShannon Nelson 	strscpy(drvinfo->fw_version, ionic->idev.dev_info.fw_version,
794d03e00aSShannon Nelson 		sizeof(drvinfo->fw_version));
80799c230eSShannon Nelson 	strscpy(drvinfo->bus_info, ionic_bus_info(ionic),
814d03e00aSShannon Nelson 		sizeof(drvinfo->bus_info));
824d03e00aSShannon Nelson }
834d03e00aSShannon Nelson 
ionic_get_regs_len(struct net_device * netdev)844d03e00aSShannon Nelson static int ionic_get_regs_len(struct net_device *netdev)
854d03e00aSShannon Nelson {
864d03e00aSShannon Nelson 	return (IONIC_DEV_INFO_REG_COUNT + IONIC_DEV_CMD_REG_COUNT) * sizeof(u32);
874d03e00aSShannon Nelson }
884d03e00aSShannon Nelson 
ionic_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)894d03e00aSShannon Nelson static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
904d03e00aSShannon Nelson 			   void *p)
914d03e00aSShannon Nelson {
924d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
9381bd4b07SShannon Nelson 	struct ionic_dev *idev;
94f85ae16fSShannon Nelson 	unsigned int offset;
954d03e00aSShannon Nelson 	unsigned int size;
964d03e00aSShannon Nelson 
974d03e00aSShannon Nelson 	regs->version = IONIC_DEV_CMD_REG_VERSION;
984d03e00aSShannon Nelson 
9981bd4b07SShannon Nelson 	idev = &lif->ionic->idev;
10081bd4b07SShannon Nelson 	if (!idev->dev_info_regs)
10181bd4b07SShannon Nelson 		return;
10281bd4b07SShannon Nelson 
103f85ae16fSShannon Nelson 	offset = 0;
1044d03e00aSShannon Nelson 	size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
105f85ae16fSShannon Nelson 	memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);
1064d03e00aSShannon Nelson 
107f85ae16fSShannon Nelson 	offset += size;
1084d03e00aSShannon Nelson 	size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
10981bd4b07SShannon Nelson 	memcpy_fromio(p + offset, idev->dev_cmd_regs->words, size);
1104d03e00aSShannon Nelson }
1114d03e00aSShannon Nelson 
ionic_get_link_ext_stats(struct net_device * netdev,struct ethtool_link_ext_stats * stats)112132b4ebfSNitya Sunkad static void ionic_get_link_ext_stats(struct net_device *netdev,
113132b4ebfSNitya Sunkad 				     struct ethtool_link_ext_stats *stats)
114132b4ebfSNitya Sunkad {
115132b4ebfSNitya Sunkad 	struct ionic_lif *lif = netdev_priv(netdev);
116132b4ebfSNitya Sunkad 
117132b4ebfSNitya Sunkad 	if (lif->ionic->pdev->is_physfn)
118132b4ebfSNitya Sunkad 		stats->link_down_events = lif->link_down_count;
119132b4ebfSNitya Sunkad }
120132b4ebfSNitya Sunkad 
ionic_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * ks)1214d03e00aSShannon Nelson static int ionic_get_link_ksettings(struct net_device *netdev,
1224d03e00aSShannon Nelson 				    struct ethtool_link_ksettings *ks)
1234d03e00aSShannon Nelson {
1244d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
1254d03e00aSShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
1264d03e00aSShannon Nelson 	int copper_seen = 0;
1274d03e00aSShannon Nelson 
1284d03e00aSShannon Nelson 	ethtool_link_ksettings_zero_link_mode(ks, supported);
1294d03e00aSShannon Nelson 
1302bcbf42aSShannon Nelson 	if (!idev->port_info) {
1312bcbf42aSShannon Nelson 		netdev_err(netdev, "port_info not initialized\n");
1322bcbf42aSShannon Nelson 		return -EOPNOTSUPP;
1332bcbf42aSShannon Nelson 	}
1342bcbf42aSShannon Nelson 
1354d03e00aSShannon Nelson 	/* The port_info data is found in a DMA space that the NIC keeps
1364d03e00aSShannon Nelson 	 * up-to-date, so there's no need to request the data from the
1374d03e00aSShannon Nelson 	 * NIC, we already have it in our memory space.
1384d03e00aSShannon Nelson 	 */
1394d03e00aSShannon Nelson 
1404d03e00aSShannon Nelson 	switch (le16_to_cpu(idev->port_info->status.xcvr.pid)) {
1414d03e00aSShannon Nelson 		/* Copper */
1424d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_CR4:
1434d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1444d03e00aSShannon Nelson 						     100000baseCR4_Full);
1454d03e00aSShannon Nelson 		copper_seen++;
1464d03e00aSShannon Nelson 		break;
1474d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_40GBASE_CR4:
1484d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1494d03e00aSShannon Nelson 						     40000baseCR4_Full);
1504d03e00aSShannon Nelson 		copper_seen++;
1514d03e00aSShannon Nelson 		break;
1524d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_25GBASE_CR_S:
1534d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_25GBASE_CR_L:
1544d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_25GBASE_CR_N:
1554d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1564d03e00aSShannon Nelson 						     25000baseCR_Full);
1574d03e00aSShannon Nelson 		copper_seen++;
1584d03e00aSShannon Nelson 		break;
1594d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_AOC:
1604d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_CU:
1614d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1624d03e00aSShannon Nelson 						     10000baseCR_Full);
1634d03e00aSShannon Nelson 		copper_seen++;
1644d03e00aSShannon Nelson 		break;
1654d03e00aSShannon Nelson 
1664d03e00aSShannon Nelson 		/* Fibre */
1674d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_SR4:
1684d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_AOC:
1694d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1704d03e00aSShannon Nelson 						     100000baseSR4_Full);
1714d03e00aSShannon Nelson 		break;
172cba155d5SShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_CWDM4:
173cba155d5SShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_PSM4:
1744d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_LR4:
1754d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1764d03e00aSShannon Nelson 						     100000baseLR4_ER4_Full);
1774d03e00aSShannon Nelson 		break;
1784d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_100G_ER4:
1794d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1804d03e00aSShannon Nelson 						     100000baseLR4_ER4_Full);
1814d03e00aSShannon Nelson 		break;
1824d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_40GBASE_SR4:
1834d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_40GBASE_AOC:
1844d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1854d03e00aSShannon Nelson 						     40000baseSR4_Full);
1864d03e00aSShannon Nelson 		break;
1874d03e00aSShannon Nelson 	case IONIC_XCVR_PID_QSFP_40GBASE_LR4:
1884d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1894d03e00aSShannon Nelson 						     40000baseLR4_Full);
1904d03e00aSShannon Nelson 		break;
1914d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_25GBASE_SR:
1924d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_25GBASE_AOC:
193cba155d5SShannon Nelson 	case IONIC_XCVR_PID_SFP_25GBASE_ACC:
1944d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1954d03e00aSShannon Nelson 						     25000baseSR_Full);
1964d03e00aSShannon Nelson 		break;
1974d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_SR:
1984d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
1994d03e00aSShannon Nelson 						     10000baseSR_Full);
2004d03e00aSShannon Nelson 		break;
2014d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_LR:
2024d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
2034d03e00aSShannon Nelson 						     10000baseLR_Full);
2044d03e00aSShannon Nelson 		break;
2054d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_LRM:
2064d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
2074d03e00aSShannon Nelson 						     10000baseLRM_Full);
2084d03e00aSShannon Nelson 		break;
2094d03e00aSShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_ER:
2104d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
2114d03e00aSShannon Nelson 						     10000baseER_Full);
2124d03e00aSShannon Nelson 		break;
213acc606d3SShannon Nelson 	case IONIC_XCVR_PID_SFP_10GBASE_T:
214acc606d3SShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
215acc606d3SShannon Nelson 						     10000baseT_Full);
216acc606d3SShannon Nelson 		break;
217acc606d3SShannon Nelson 	case IONIC_XCVR_PID_SFP_1000BASE_T:
218acc606d3SShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported,
219acc606d3SShannon Nelson 						     1000baseT_Full);
220acc606d3SShannon Nelson 		break;
2214d03e00aSShannon Nelson 	case IONIC_XCVR_PID_UNKNOWN:
2224d03e00aSShannon Nelson 		/* This means there's no module plugged in */
2234d03e00aSShannon Nelson 		break;
2244d03e00aSShannon Nelson 	default:
2254d03e00aSShannon Nelson 		dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n",
2264d03e00aSShannon Nelson 			 idev->port_info->status.xcvr.pid,
2274d03e00aSShannon Nelson 			 idev->port_info->status.xcvr.pid);
2284d03e00aSShannon Nelson 		break;
2294d03e00aSShannon Nelson 	}
2304d03e00aSShannon Nelson 
2314973056cSSean Anderson 	linkmode_copy(ks->link_modes.advertising, ks->link_modes.supported);
2324d03e00aSShannon Nelson 
2334d03e00aSShannon Nelson 	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
2344d03e00aSShannon Nelson 	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
2354d03e00aSShannon Nelson 	if (idev->port_info->config.fec_type == IONIC_PORT_FEC_TYPE_FC)
2364d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_BASER);
2374d03e00aSShannon Nelson 	else if (idev->port_info->config.fec_type == IONIC_PORT_FEC_TYPE_RS)
2384d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
2394d03e00aSShannon Nelson 
2404d03e00aSShannon Nelson 	ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE);
2414d03e00aSShannon Nelson 	ethtool_link_ksettings_add_link_mode(ks, supported, Pause);
2424d03e00aSShannon Nelson 
2434d03e00aSShannon Nelson 	if (idev->port_info->status.xcvr.phy == IONIC_PHY_TYPE_COPPER ||
2444d03e00aSShannon Nelson 	    copper_seen)
2454d03e00aSShannon Nelson 		ks->base.port = PORT_DA;
2464d03e00aSShannon Nelson 	else if (idev->port_info->status.xcvr.phy == IONIC_PHY_TYPE_FIBER)
2474d03e00aSShannon Nelson 		ks->base.port = PORT_FIBRE;
2484d03e00aSShannon Nelson 	else
2494d03e00aSShannon Nelson 		ks->base.port = PORT_NONE;
2504d03e00aSShannon Nelson 
2514d03e00aSShannon Nelson 	if (ks->base.port != PORT_NONE) {
2524d03e00aSShannon Nelson 		ks->base.speed = le32_to_cpu(lif->info->status.link_speed);
2534d03e00aSShannon Nelson 
2544d03e00aSShannon Nelson 		if (le16_to_cpu(lif->info->status.link_status))
2554d03e00aSShannon Nelson 			ks->base.duplex = DUPLEX_FULL;
2564d03e00aSShannon Nelson 		else
2574d03e00aSShannon Nelson 			ks->base.duplex = DUPLEX_UNKNOWN;
2584d03e00aSShannon Nelson 
2594d03e00aSShannon Nelson 		ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
2604d03e00aSShannon Nelson 
2614d03e00aSShannon Nelson 		if (idev->port_info->config.an_enable) {
2624d03e00aSShannon Nelson 			ethtool_link_ksettings_add_link_mode(ks, advertising,
2634d03e00aSShannon Nelson 							     Autoneg);
2644d03e00aSShannon Nelson 			ks->base.autoneg = AUTONEG_ENABLE;
2654d03e00aSShannon Nelson 		}
2664d03e00aSShannon Nelson 	}
2674d03e00aSShannon Nelson 
2684d03e00aSShannon Nelson 	return 0;
2694d03e00aSShannon Nelson }
2704d03e00aSShannon Nelson 
ionic_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * ks)2714d03e00aSShannon Nelson static int ionic_set_link_ksettings(struct net_device *netdev,
2724d03e00aSShannon Nelson 				    const struct ethtool_link_ksettings *ks)
2734d03e00aSShannon Nelson {
2744d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
27525cc5a5fSShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
2764d03e00aSShannon Nelson 	struct ionic *ionic = lif->ionic;
2774d03e00aSShannon Nelson 	int err = 0;
2784d03e00aSShannon Nelson 
279f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
280f5123686SShannon Nelson 		return -EBUSY;
281f5123686SShannon Nelson 
2824d03e00aSShannon Nelson 	/* set autoneg */
2834d03e00aSShannon Nelson 	if (ks->base.autoneg != idev->port_info->config.an_enable) {
2844d03e00aSShannon Nelson 		mutex_lock(&ionic->dev_cmd_lock);
2854d03e00aSShannon Nelson 		ionic_dev_cmd_port_autoneg(idev, ks->base.autoneg);
2864d03e00aSShannon Nelson 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
2874d03e00aSShannon Nelson 		mutex_unlock(&ionic->dev_cmd_lock);
2884d03e00aSShannon Nelson 		if (err)
2894d03e00aSShannon Nelson 			return err;
2904d03e00aSShannon Nelson 	}
2914d03e00aSShannon Nelson 
2924d03e00aSShannon Nelson 	/* set speed */
2934d03e00aSShannon Nelson 	if (ks->base.speed != le32_to_cpu(idev->port_info->config.speed)) {
2944d03e00aSShannon Nelson 		mutex_lock(&ionic->dev_cmd_lock);
2954d03e00aSShannon Nelson 		ionic_dev_cmd_port_speed(idev, ks->base.speed);
2964d03e00aSShannon Nelson 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
2974d03e00aSShannon Nelson 		mutex_unlock(&ionic->dev_cmd_lock);
2984d03e00aSShannon Nelson 		if (err)
2994d03e00aSShannon Nelson 			return err;
3004d03e00aSShannon Nelson 	}
3014d03e00aSShannon Nelson 
3024d03e00aSShannon Nelson 	return 0;
3034d03e00aSShannon Nelson }
3044d03e00aSShannon Nelson 
ionic_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)3054d03e00aSShannon Nelson static void ionic_get_pauseparam(struct net_device *netdev,
3064d03e00aSShannon Nelson 				 struct ethtool_pauseparam *pause)
3074d03e00aSShannon Nelson {
3084d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
3094d03e00aSShannon Nelson 	u8 pause_type;
3104d03e00aSShannon Nelson 
3114d03e00aSShannon Nelson 	pause->autoneg = 0;
3124d03e00aSShannon Nelson 
3134d03e00aSShannon Nelson 	pause_type = lif->ionic->idev.port_info->config.pause_type;
3144d03e00aSShannon Nelson 	if (pause_type) {
3152aaa05a1SShannon Nelson 		pause->rx_pause = (pause_type & IONIC_PAUSE_F_RX) ? 1 : 0;
3162aaa05a1SShannon Nelson 		pause->tx_pause = (pause_type & IONIC_PAUSE_F_TX) ? 1 : 0;
3174d03e00aSShannon Nelson 	}
3184d03e00aSShannon Nelson }
3194d03e00aSShannon Nelson 
ionic_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)3204d03e00aSShannon Nelson static int ionic_set_pauseparam(struct net_device *netdev,
3214d03e00aSShannon Nelson 				struct ethtool_pauseparam *pause)
3224d03e00aSShannon Nelson {
3234d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
3244d03e00aSShannon Nelson 	struct ionic *ionic = lif->ionic;
3254d03e00aSShannon Nelson 	u32 requested_pause;
3264d03e00aSShannon Nelson 	int err;
3274d03e00aSShannon Nelson 
328f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
329f5123686SShannon Nelson 		return -EBUSY;
330f5123686SShannon Nelson 
3314d03e00aSShannon Nelson 	if (pause->autoneg)
3324d03e00aSShannon Nelson 		return -EOPNOTSUPP;
3334d03e00aSShannon Nelson 
3344d03e00aSShannon Nelson 	/* change both at the same time */
3354d03e00aSShannon Nelson 	requested_pause = IONIC_PORT_PAUSE_TYPE_LINK;
3364d03e00aSShannon Nelson 	if (pause->rx_pause)
3374d03e00aSShannon Nelson 		requested_pause |= IONIC_PAUSE_F_RX;
3384d03e00aSShannon Nelson 	if (pause->tx_pause)
3394d03e00aSShannon Nelson 		requested_pause |= IONIC_PAUSE_F_TX;
3404d03e00aSShannon Nelson 
3414d03e00aSShannon Nelson 	if (requested_pause == lif->ionic->idev.port_info->config.pause_type)
3424d03e00aSShannon Nelson 		return 0;
3434d03e00aSShannon Nelson 
3444d03e00aSShannon Nelson 	mutex_lock(&ionic->dev_cmd_lock);
3454d03e00aSShannon Nelson 	ionic_dev_cmd_port_pause(&lif->ionic->idev, requested_pause);
3464d03e00aSShannon Nelson 	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
3474d03e00aSShannon Nelson 	mutex_unlock(&ionic->dev_cmd_lock);
3484d03e00aSShannon Nelson 	if (err)
3494d03e00aSShannon Nelson 		return err;
3504d03e00aSShannon Nelson 
3514d03e00aSShannon Nelson 	return 0;
3524d03e00aSShannon Nelson }
3534d03e00aSShannon Nelson 
ionic_get_fecparam(struct net_device * netdev,struct ethtool_fecparam * fec)354e95f922fSShannon Nelson static int ionic_get_fecparam(struct net_device *netdev,
355e95f922fSShannon Nelson 			      struct ethtool_fecparam *fec)
356e95f922fSShannon Nelson {
357e95f922fSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
358e95f922fSShannon Nelson 
359e95f922fSShannon Nelson 	switch (lif->ionic->idev.port_info->config.fec_type) {
360e95f922fSShannon Nelson 	case IONIC_PORT_FEC_TYPE_NONE:
361e95f922fSShannon Nelson 		fec->active_fec = ETHTOOL_FEC_OFF;
362e95f922fSShannon Nelson 		break;
363e95f922fSShannon Nelson 	case IONIC_PORT_FEC_TYPE_RS:
364e95f922fSShannon Nelson 		fec->active_fec = ETHTOOL_FEC_RS;
365e95f922fSShannon Nelson 		break;
366e95f922fSShannon Nelson 	case IONIC_PORT_FEC_TYPE_FC:
367e95f922fSShannon Nelson 		fec->active_fec = ETHTOOL_FEC_BASER;
368e95f922fSShannon Nelson 		break;
369e95f922fSShannon Nelson 	}
370e95f922fSShannon Nelson 
371e95f922fSShannon Nelson 	fec->fec = ETHTOOL_FEC_OFF | ETHTOOL_FEC_RS | ETHTOOL_FEC_BASER;
372e95f922fSShannon Nelson 
373e95f922fSShannon Nelson 	return 0;
374e95f922fSShannon Nelson }
375e95f922fSShannon Nelson 
ionic_set_fecparam(struct net_device * netdev,struct ethtool_fecparam * fec)376e95f922fSShannon Nelson static int ionic_set_fecparam(struct net_device *netdev,
377e95f922fSShannon Nelson 			      struct ethtool_fecparam *fec)
378e95f922fSShannon Nelson {
379e95f922fSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
380e95f922fSShannon Nelson 	u8 fec_type;
381e95f922fSShannon Nelson 	int ret = 0;
382e95f922fSShannon Nelson 
383f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
384f5123686SShannon Nelson 		return -EBUSY;
385f5123686SShannon Nelson 
386e95f922fSShannon Nelson 	if (lif->ionic->idev.port_info->config.an_enable) {
387e95f922fSShannon Nelson 		netdev_err(netdev, "FEC request not allowed while autoneg is enabled\n");
388e95f922fSShannon Nelson 		return -EINVAL;
389e95f922fSShannon Nelson 	}
390e95f922fSShannon Nelson 
391e95f922fSShannon Nelson 	switch (fec->fec) {
392e95f922fSShannon Nelson 	case ETHTOOL_FEC_NONE:
393e95f922fSShannon Nelson 		fec_type = IONIC_PORT_FEC_TYPE_NONE;
394e95f922fSShannon Nelson 		break;
395e95f922fSShannon Nelson 	case ETHTOOL_FEC_OFF:
396e95f922fSShannon Nelson 		fec_type = IONIC_PORT_FEC_TYPE_NONE;
397e95f922fSShannon Nelson 		break;
398e95f922fSShannon Nelson 	case ETHTOOL_FEC_RS:
399e95f922fSShannon Nelson 		fec_type = IONIC_PORT_FEC_TYPE_RS;
400e95f922fSShannon Nelson 		break;
401e95f922fSShannon Nelson 	case ETHTOOL_FEC_BASER:
402e95f922fSShannon Nelson 		fec_type = IONIC_PORT_FEC_TYPE_FC;
403e95f922fSShannon Nelson 		break;
404e95f922fSShannon Nelson 	case ETHTOOL_FEC_AUTO:
405e95f922fSShannon Nelson 	default:
406e95f922fSShannon Nelson 		netdev_err(netdev, "FEC request 0x%04x not supported\n",
407e95f922fSShannon Nelson 			   fec->fec);
408e95f922fSShannon Nelson 		return -EINVAL;
409e95f922fSShannon Nelson 	}
410e95f922fSShannon Nelson 
411e95f922fSShannon Nelson 	if (fec_type != lif->ionic->idev.port_info->config.fec_type) {
412e95f922fSShannon Nelson 		mutex_lock(&lif->ionic->dev_cmd_lock);
413e95f922fSShannon Nelson 		ionic_dev_cmd_port_fec(&lif->ionic->idev, fec_type);
414e95f922fSShannon Nelson 		ret = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
415e95f922fSShannon Nelson 		mutex_unlock(&lif->ionic->dev_cmd_lock);
416e95f922fSShannon Nelson 	}
417e95f922fSShannon Nelson 
418e95f922fSShannon Nelson 	return ret;
419e95f922fSShannon Nelson }
420e95f922fSShannon Nelson 
ionic_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * coalesce,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)4214d03e00aSShannon Nelson static int ionic_get_coalesce(struct net_device *netdev,
422f3ccfda1SYufeng Mo 			      struct ethtool_coalesce *coalesce,
423f3ccfda1SYufeng Mo 			      struct kernel_ethtool_coalesce *kernel_coal,
424f3ccfda1SYufeng Mo 			      struct netlink_ext_ack *extack)
4254d03e00aSShannon Nelson {
4264d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
4274d03e00aSShannon Nelson 
428fe8c30b5SShannon Nelson 	coalesce->tx_coalesce_usecs = lif->tx_coalesce_usecs;
4294d03e00aSShannon Nelson 	coalesce->rx_coalesce_usecs = lif->rx_coalesce_usecs;
4304d03e00aSShannon Nelson 
43104a83459SShannon Nelson 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
43204a83459SShannon Nelson 		coalesce->use_adaptive_tx_coalesce = test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
43304a83459SShannon Nelson 	else
43404a83459SShannon Nelson 		coalesce->use_adaptive_tx_coalesce = 0;
43504a83459SShannon Nelson 
43604a83459SShannon Nelson 	coalesce->use_adaptive_rx_coalesce = test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
43704a83459SShannon Nelson 
4384d03e00aSShannon Nelson 	return 0;
4394d03e00aSShannon Nelson }
4404d03e00aSShannon Nelson 
ionic_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * coalesce,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)4418c15440bSShannon Nelson static int ionic_set_coalesce(struct net_device *netdev,
442f3ccfda1SYufeng Mo 			      struct ethtool_coalesce *coalesce,
443f3ccfda1SYufeng Mo 			      struct kernel_ethtool_coalesce *kernel_coal,
444f3ccfda1SYufeng Mo 			      struct netlink_ext_ack *extack)
4458c15440bSShannon Nelson {
4468c15440bSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
4478c15440bSShannon Nelson 	struct ionic_identity *ident;
44804a83459SShannon Nelson 	u32 rx_coal, rx_dim;
44904a83459SShannon Nelson 	u32 tx_coal, tx_dim;
4508c15440bSShannon Nelson 	unsigned int i;
4518c15440bSShannon Nelson 
4528c15440bSShannon Nelson 	ident = &lif->ionic->ident;
4538c15440bSShannon Nelson 	if (ident->dev.intr_coal_div == 0) {
4548c15440bSShannon Nelson 		netdev_warn(netdev, "bad HW value in dev.intr_coal_div = %d\n",
4558c15440bSShannon Nelson 			    ident->dev.intr_coal_div);
4568c15440bSShannon Nelson 		return -EIO;
4578c15440bSShannon Nelson 	}
4588c15440bSShannon Nelson 
45904a83459SShannon Nelson 	/* Tx normally shares Rx interrupt, so only change Rx if not split */
460fe8c30b5SShannon Nelson 	if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) &&
46104a83459SShannon Nelson 	    (coalesce->tx_coalesce_usecs != lif->rx_coalesce_usecs ||
46204a83459SShannon Nelson 	     coalesce->use_adaptive_tx_coalesce)) {
46304a83459SShannon Nelson 		netdev_warn(netdev, "only rx parameters can be changed\n");
4648c15440bSShannon Nelson 		return -EINVAL;
4658c15440bSShannon Nelson 	}
4668c15440bSShannon Nelson 
467fe8c30b5SShannon Nelson 	/* Convert the usec request to a HW usable value.  If they asked
468780eded3SShannon Nelson 	 * for non-zero and it resolved to zero, bump it up
469780eded3SShannon Nelson 	 */
470fe8c30b5SShannon Nelson 	rx_coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->rx_coalesce_usecs);
471fe8c30b5SShannon Nelson 	if (!rx_coal && coalesce->rx_coalesce_usecs)
472fe8c30b5SShannon Nelson 		rx_coal = 1;
473fe8c30b5SShannon Nelson 	tx_coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->tx_coalesce_usecs);
474fe8c30b5SShannon Nelson 	if (!tx_coal && coalesce->tx_coalesce_usecs)
475fe8c30b5SShannon Nelson 		tx_coal = 1;
4768c15440bSShannon Nelson 
477fe8c30b5SShannon Nelson 	if (rx_coal > IONIC_INTR_CTRL_COAL_MAX ||
478fe8c30b5SShannon Nelson 	    tx_coal > IONIC_INTR_CTRL_COAL_MAX)
4798c15440bSShannon Nelson 		return -ERANGE;
4808c15440bSShannon Nelson 
481fe8c30b5SShannon Nelson 	/* Save the new values */
482780eded3SShannon Nelson 	lif->rx_coalesce_usecs = coalesce->rx_coalesce_usecs;
483fe8c30b5SShannon Nelson 	lif->rx_coalesce_hw = rx_coal;
4848c15440bSShannon Nelson 
485fe8c30b5SShannon Nelson 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
486fe8c30b5SShannon Nelson 		lif->tx_coalesce_usecs = coalesce->tx_coalesce_usecs;
487fe8c30b5SShannon Nelson 	else
488fe8c30b5SShannon Nelson 		lif->tx_coalesce_usecs = coalesce->rx_coalesce_usecs;
489fe8c30b5SShannon Nelson 	lif->tx_coalesce_hw = tx_coal;
490fe8c30b5SShannon Nelson 
49104a83459SShannon Nelson 	if (coalesce->use_adaptive_rx_coalesce) {
49204a83459SShannon Nelson 		set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
49304a83459SShannon Nelson 		rx_dim = rx_coal;
49404a83459SShannon Nelson 	} else {
49504a83459SShannon Nelson 		clear_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
49604a83459SShannon Nelson 		rx_dim = 0;
49704a83459SShannon Nelson 	}
49804a83459SShannon Nelson 
49904a83459SShannon Nelson 	if (coalesce->use_adaptive_tx_coalesce) {
50004a83459SShannon Nelson 		set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
50104a83459SShannon Nelson 		tx_dim = tx_coal;
50204a83459SShannon Nelson 	} else {
50304a83459SShannon Nelson 		clear_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
50404a83459SShannon Nelson 		tx_dim = 0;
50504a83459SShannon Nelson 	}
50604a83459SShannon Nelson 
507fe8c30b5SShannon Nelson 	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
508fe8c30b5SShannon Nelson 		for (i = 0; i < lif->nxqs; i++) {
50904a83459SShannon Nelson 			if (lif->rxqcqs[i]->flags & IONIC_QCQ_F_INTR) {
510fe8c30b5SShannon Nelson 				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
51104a83459SShannon Nelson 						     lif->rxqcqs[i]->intr.index,
51204a83459SShannon Nelson 						     lif->rx_coalesce_hw);
51304a83459SShannon Nelson 				lif->rxqcqs[i]->intr.dim_coal_hw = rx_dim;
51404a83459SShannon Nelson 			}
51504a83459SShannon Nelson 
51604a83459SShannon Nelson 			if (lif->txqcqs[i]->flags & IONIC_QCQ_F_INTR) {
51704a83459SShannon Nelson 				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
51804a83459SShannon Nelson 						     lif->txqcqs[i]->intr.index,
519fe8c30b5SShannon Nelson 						     lif->tx_coalesce_hw);
52004a83459SShannon Nelson 				lif->txqcqs[i]->intr.dim_coal_hw = tx_dim;
521fe8c30b5SShannon Nelson 			}
522fe8c30b5SShannon Nelson 		}
523fe8c30b5SShannon Nelson 	}
524fe8c30b5SShannon Nelson 
5258c15440bSShannon Nelson 	return 0;
5268c15440bSShannon Nelson }
5278c15440bSShannon Nelson 
ionic_validate_cmb_config(struct ionic_lif * lif,struct ionic_queue_params * qparam)52840bc471dSShannon Nelson static int ionic_validate_cmb_config(struct ionic_lif *lif,
52940bc471dSShannon Nelson 				     struct ionic_queue_params *qparam)
53040bc471dSShannon Nelson {
53140bc471dSShannon Nelson 	int pages_have, pages_required = 0;
53240bc471dSShannon Nelson 	unsigned long sz;
53340bc471dSShannon Nelson 
53440bc471dSShannon Nelson 	if (!lif->ionic->idev.cmb_inuse &&
53540bc471dSShannon Nelson 	    (qparam->cmb_tx || qparam->cmb_rx)) {
53640bc471dSShannon Nelson 		netdev_info(lif->netdev, "CMB rings are not supported on this device\n");
53740bc471dSShannon Nelson 		return -EOPNOTSUPP;
53840bc471dSShannon Nelson 	}
53940bc471dSShannon Nelson 
54040bc471dSShannon Nelson 	if (qparam->cmb_tx) {
54140bc471dSShannon Nelson 		if (!(lif->qtype_info[IONIC_QTYPE_TXQ].features & IONIC_QIDENT_F_CMB)) {
54240bc471dSShannon Nelson 			netdev_info(lif->netdev,
54340bc471dSShannon Nelson 				    "CMB rings for tx-push are not supported on this device\n");
54440bc471dSShannon Nelson 			return -EOPNOTSUPP;
54540bc471dSShannon Nelson 		}
54640bc471dSShannon Nelson 
54740bc471dSShannon Nelson 		sz = sizeof(struct ionic_txq_desc) * qparam->ntxq_descs * qparam->nxqs;
54840bc471dSShannon Nelson 		pages_required += ALIGN(sz, PAGE_SIZE) / PAGE_SIZE;
54940bc471dSShannon Nelson 	}
55040bc471dSShannon Nelson 
55140bc471dSShannon Nelson 	if (qparam->cmb_rx) {
55240bc471dSShannon Nelson 		if (!(lif->qtype_info[IONIC_QTYPE_RXQ].features & IONIC_QIDENT_F_CMB)) {
55340bc471dSShannon Nelson 			netdev_info(lif->netdev,
55440bc471dSShannon Nelson 				    "CMB rings for rx-push are not supported on this device\n");
55540bc471dSShannon Nelson 			return -EOPNOTSUPP;
55640bc471dSShannon Nelson 		}
55740bc471dSShannon Nelson 
55840bc471dSShannon Nelson 		sz = sizeof(struct ionic_rxq_desc) * qparam->nrxq_descs * qparam->nxqs;
55940bc471dSShannon Nelson 		pages_required += ALIGN(sz, PAGE_SIZE) / PAGE_SIZE;
56040bc471dSShannon Nelson 	}
56140bc471dSShannon Nelson 
56240bc471dSShannon Nelson 	pages_have = lif->ionic->bars[IONIC_PCI_BAR_CMB].len / PAGE_SIZE;
56340bc471dSShannon Nelson 	if (pages_required > pages_have) {
56440bc471dSShannon Nelson 		netdev_info(lif->netdev,
56540bc471dSShannon Nelson 			    "Not enough CMB pages for number of queues and size of descriptor rings, need %d have %d",
56640bc471dSShannon Nelson 			    pages_required, pages_have);
56740bc471dSShannon Nelson 		return -ENOMEM;
56840bc471dSShannon Nelson 	}
56940bc471dSShannon Nelson 
57040bc471dSShannon Nelson 	return pages_required;
57140bc471dSShannon Nelson }
57240bc471dSShannon Nelson 
ionic_cmb_rings_toggle(struct ionic_lif * lif,bool cmb_tx,bool cmb_rx)57340bc471dSShannon Nelson static int ionic_cmb_rings_toggle(struct ionic_lif *lif, bool cmb_tx, bool cmb_rx)
57440bc471dSShannon Nelson {
57540bc471dSShannon Nelson 	struct ionic_queue_params qparam;
57640bc471dSShannon Nelson 	int pages_used;
57740bc471dSShannon Nelson 
57840bc471dSShannon Nelson 	if (netif_running(lif->netdev)) {
57940bc471dSShannon Nelson 		netdev_info(lif->netdev, "Please stop device to toggle CMB for tx/rx-push\n");
58040bc471dSShannon Nelson 		return -EBUSY;
58140bc471dSShannon Nelson 	}
58240bc471dSShannon Nelson 
58340bc471dSShannon Nelson 	ionic_init_queue_params(lif, &qparam);
58440bc471dSShannon Nelson 	qparam.cmb_tx = cmb_tx;
58540bc471dSShannon Nelson 	qparam.cmb_rx = cmb_rx;
58640bc471dSShannon Nelson 	pages_used = ionic_validate_cmb_config(lif, &qparam);
58740bc471dSShannon Nelson 	if (pages_used < 0)
58840bc471dSShannon Nelson 		return pages_used;
58940bc471dSShannon Nelson 
59040bc471dSShannon Nelson 	if (cmb_tx)
59140bc471dSShannon Nelson 		set_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state);
59240bc471dSShannon Nelson 	else
59340bc471dSShannon Nelson 		clear_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state);
59440bc471dSShannon Nelson 
59540bc471dSShannon Nelson 	if (cmb_rx)
59640bc471dSShannon Nelson 		set_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state);
59740bc471dSShannon Nelson 	else
59840bc471dSShannon Nelson 		clear_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state);
59940bc471dSShannon Nelson 
60040bc471dSShannon Nelson 	if (cmb_tx || cmb_rx)
60140bc471dSShannon Nelson 		netdev_info(lif->netdev, "Enabling CMB %s %s rings - %d pages\n",
60240bc471dSShannon Nelson 			    cmb_tx ? "TX" : "", cmb_rx ? "RX" : "", pages_used);
60340bc471dSShannon Nelson 	else
60440bc471dSShannon Nelson 		netdev_info(lif->netdev, "Disabling CMB rings\n");
60540bc471dSShannon Nelson 
60640bc471dSShannon Nelson 	return 0;
60740bc471dSShannon Nelson }
60840bc471dSShannon Nelson 
ionic_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)6094d03e00aSShannon Nelson static void ionic_get_ringparam(struct net_device *netdev,
61074624944SHao Chen 				struct ethtool_ringparam *ring,
61174624944SHao Chen 				struct kernel_ethtool_ringparam *kernel_ring,
61274624944SHao Chen 				struct netlink_ext_ack *extack)
6134d03e00aSShannon Nelson {
6144d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
6154d03e00aSShannon Nelson 
6165b3f3f2aSShannon Nelson 	ring->tx_max_pending = IONIC_MAX_TX_DESC;
6174d03e00aSShannon Nelson 	ring->tx_pending = lif->ntxq_descs;
6185b3f3f2aSShannon Nelson 	ring->rx_max_pending = IONIC_MAX_RX_DESC;
6194d03e00aSShannon Nelson 	ring->rx_pending = lif->nrxq_descs;
62040bc471dSShannon Nelson 	kernel_ring->tx_push = test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state);
62140bc471dSShannon Nelson 	kernel_ring->rx_push = test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state);
6224d03e00aSShannon Nelson }
6234d03e00aSShannon Nelson 
ionic_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)6244d03e00aSShannon Nelson static int ionic_set_ringparam(struct net_device *netdev,
62574624944SHao Chen 			       struct ethtool_ringparam *ring,
62674624944SHao Chen 			       struct kernel_ethtool_ringparam *kernel_ring,
62774624944SHao Chen 			       struct netlink_ext_ack *extack)
6284d03e00aSShannon Nelson {
6294d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
630a34e25abSShannon Nelson 	struct ionic_queue_params qparam;
631a34e25abSShannon Nelson 	int err;
632a34e25abSShannon Nelson 
633f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
634f5123686SShannon Nelson 		return -EBUSY;
635f5123686SShannon Nelson 
636a34e25abSShannon Nelson 	ionic_init_queue_params(lif, &qparam);
6374d03e00aSShannon Nelson 
6384d03e00aSShannon Nelson 	if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
6394d03e00aSShannon Nelson 		netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n");
6404d03e00aSShannon Nelson 		return -EINVAL;
6414d03e00aSShannon Nelson 	}
6424d03e00aSShannon Nelson 
6434d03e00aSShannon Nelson 	if (!is_power_of_2(ring->tx_pending) ||
6444d03e00aSShannon Nelson 	    !is_power_of_2(ring->rx_pending)) {
6454d03e00aSShannon Nelson 		netdev_info(netdev, "Descriptor count must be a power of 2\n");
6464d03e00aSShannon Nelson 		return -EINVAL;
6474d03e00aSShannon Nelson 	}
6484d03e00aSShannon Nelson 
6494d03e00aSShannon Nelson 	/* if nothing to do return success */
6504d03e00aSShannon Nelson 	if (ring->tx_pending == lif->ntxq_descs &&
65140bc471dSShannon Nelson 	    ring->rx_pending == lif->nrxq_descs &&
65240bc471dSShannon Nelson 	    kernel_ring->tx_push == test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state) &&
65340bc471dSShannon Nelson 	    kernel_ring->rx_push == test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state))
6544d03e00aSShannon Nelson 		return 0;
6554d03e00aSShannon Nelson 
65640bc471dSShannon Nelson 	qparam.ntxq_descs = ring->tx_pending;
65740bc471dSShannon Nelson 	qparam.nrxq_descs = ring->rx_pending;
65840bc471dSShannon Nelson 	qparam.cmb_tx = kernel_ring->tx_push;
65940bc471dSShannon Nelson 	qparam.cmb_rx = kernel_ring->rx_push;
66040bc471dSShannon Nelson 
66140bc471dSShannon Nelson 	err = ionic_validate_cmb_config(lif, &qparam);
66240bc471dSShannon Nelson 	if (err < 0)
66340bc471dSShannon Nelson 		return err;
66440bc471dSShannon Nelson 
66540bc471dSShannon Nelson 	if (kernel_ring->tx_push != test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state) ||
66640bc471dSShannon Nelson 	    kernel_ring->rx_push != test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state)) {
66740bc471dSShannon Nelson 		err = ionic_cmb_rings_toggle(lif, kernel_ring->tx_push,
66840bc471dSShannon Nelson 					     kernel_ring->rx_push);
66940bc471dSShannon Nelson 		if (err < 0)
67040bc471dSShannon Nelson 			return err;
67140bc471dSShannon Nelson 	}
67240bc471dSShannon Nelson 
673a34e25abSShannon Nelson 	if (ring->tx_pending != lif->ntxq_descs)
674a34e25abSShannon Nelson 		netdev_info(netdev, "Changing Tx ring size from %d to %d\n",
675a34e25abSShannon Nelson 			    lif->ntxq_descs, ring->tx_pending);
676a34e25abSShannon Nelson 
677a34e25abSShannon Nelson 	if (ring->rx_pending != lif->nrxq_descs)
678a34e25abSShannon Nelson 		netdev_info(netdev, "Changing Rx ring size from %d to %d\n",
679a34e25abSShannon Nelson 			    lif->nrxq_descs, ring->rx_pending);
680a34e25abSShannon Nelson 
681a34e25abSShannon Nelson 	/* if we're not running, just set the values and return */
682a34e25abSShannon Nelson 	if (!netif_running(lif->netdev)) {
683a34e25abSShannon Nelson 		lif->ntxq_descs = ring->tx_pending;
684a34e25abSShannon Nelson 		lif->nrxq_descs = ring->rx_pending;
685a34e25abSShannon Nelson 		return 0;
686a34e25abSShannon Nelson 	}
687a34e25abSShannon Nelson 
68879a58c06SShannon Nelson 	mutex_lock(&lif->queue_lock);
689a34e25abSShannon Nelson 	err = ionic_reconfigure_queues(lif, &qparam);
69079a58c06SShannon Nelson 	mutex_unlock(&lif->queue_lock);
691a34e25abSShannon Nelson 	if (err)
692a34e25abSShannon Nelson 		netdev_info(netdev, "Ring reconfiguration failed, changes canceled: %d\n", err);
693a34e25abSShannon Nelson 
694a34e25abSShannon Nelson 	return err;
6954d03e00aSShannon Nelson }
6964d03e00aSShannon Nelson 
ionic_get_channels(struct net_device * netdev,struct ethtool_channels * ch)6974d03e00aSShannon Nelson static void ionic_get_channels(struct net_device *netdev,
6984d03e00aSShannon Nelson 			       struct ethtool_channels *ch)
6994d03e00aSShannon Nelson {
7004d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
7014d03e00aSShannon Nelson 
7024d03e00aSShannon Nelson 	/* report maximum channels */
7034d03e00aSShannon Nelson 	ch->max_combined = lif->ionic->ntxqs_per_lif;
704fe8c30b5SShannon Nelson 	ch->max_rx = lif->ionic->ntxqs_per_lif / 2;
705fe8c30b5SShannon Nelson 	ch->max_tx = lif->ionic->ntxqs_per_lif / 2;
7064d03e00aSShannon Nelson 
7074d03e00aSShannon Nelson 	/* report current channels */
708fe8c30b5SShannon Nelson 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
709fe8c30b5SShannon Nelson 		ch->rx_count = lif->nxqs;
710fe8c30b5SShannon Nelson 		ch->tx_count = lif->nxqs;
711fe8c30b5SShannon Nelson 	} else {
7124d03e00aSShannon Nelson 		ch->combined_count = lif->nxqs;
7134d03e00aSShannon Nelson 	}
714fe8c30b5SShannon Nelson }
7154d03e00aSShannon Nelson 
ionic_set_channels(struct net_device * netdev,struct ethtool_channels * ch)7164d03e00aSShannon Nelson static int ionic_set_channels(struct net_device *netdev,
7174d03e00aSShannon Nelson 			      struct ethtool_channels *ch)
7184d03e00aSShannon Nelson {
7194d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
720101b40a0SShannon Nelson 	struct ionic_queue_params qparam;
721101b40a0SShannon Nelson 	int max_cnt;
722101b40a0SShannon Nelson 	int err;
723101b40a0SShannon Nelson 
724f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
725f5123686SShannon Nelson 		return -EBUSY;
726f5123686SShannon Nelson 
727101b40a0SShannon Nelson 	ionic_init_queue_params(lif, &qparam);
7284d03e00aSShannon Nelson 
729fe8c30b5SShannon Nelson 	if (ch->rx_count != ch->tx_count) {
730fe8c30b5SShannon Nelson 		netdev_info(netdev, "The rx and tx count must be equal\n");
7314d03e00aSShannon Nelson 		return -EINVAL;
732fe8c30b5SShannon Nelson 	}
7334d03e00aSShannon Nelson 
734fe8c30b5SShannon Nelson 	if (ch->combined_count && ch->rx_count) {
735101b40a0SShannon Nelson 		netdev_info(netdev, "Use either combined or rx and tx, not both\n");
736fe8c30b5SShannon Nelson 		return -EINVAL;
737fe8c30b5SShannon Nelson 	}
738fe8c30b5SShannon Nelson 
739101b40a0SShannon Nelson 	max_cnt = lif->ionic->ntxqs_per_lif;
740101b40a0SShannon Nelson 	if (ch->combined_count) {
741101b40a0SShannon Nelson 		if (ch->combined_count > max_cnt)
742101b40a0SShannon Nelson 			return -EINVAL;
743fe8c30b5SShannon Nelson 
744101b40a0SShannon Nelson 		if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
745101b40a0SShannon Nelson 			netdev_info(lif->netdev, "Sharing queue interrupts\n");
746101b40a0SShannon Nelson 		else if (ch->combined_count == lif->nxqs)
747101b40a0SShannon Nelson 			return 0;
748101b40a0SShannon Nelson 
749101b40a0SShannon Nelson 		if (lif->nxqs != ch->combined_count)
750fe8c30b5SShannon Nelson 			netdev_info(netdev, "Changing queue count from %d to %d\n",
751101b40a0SShannon Nelson 				    lif->nxqs, ch->combined_count);
7524d03e00aSShannon Nelson 
753101b40a0SShannon Nelson 		qparam.nxqs = ch->combined_count;
75440bc471dSShannon Nelson 		qparam.intr_split = false;
755101b40a0SShannon Nelson 	} else {
756101b40a0SShannon Nelson 		max_cnt /= 2;
757101b40a0SShannon Nelson 		if (ch->rx_count > max_cnt)
758101b40a0SShannon Nelson 			return -EINVAL;
759101b40a0SShannon Nelson 
760101b40a0SShannon Nelson 		if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
761101b40a0SShannon Nelson 			netdev_info(lif->netdev, "Splitting queue interrupts\n");
762101b40a0SShannon Nelson 		else if (ch->rx_count == lif->nxqs)
763101b40a0SShannon Nelson 			return 0;
764101b40a0SShannon Nelson 
765101b40a0SShannon Nelson 		if (lif->nxqs != ch->rx_count)
766101b40a0SShannon Nelson 			netdev_info(netdev, "Changing queue count from %d to %d\n",
767101b40a0SShannon Nelson 				    lif->nxqs, ch->rx_count);
768101b40a0SShannon Nelson 
769101b40a0SShannon Nelson 		qparam.nxqs = ch->rx_count;
77040bc471dSShannon Nelson 		qparam.intr_split = true;
771101b40a0SShannon Nelson 	}
772101b40a0SShannon Nelson 
77340bc471dSShannon Nelson 	err = ionic_validate_cmb_config(lif, &qparam);
77440bc471dSShannon Nelson 	if (err < 0)
77540bc471dSShannon Nelson 		return err;
77640bc471dSShannon Nelson 
777101b40a0SShannon Nelson 	/* if we're not running, just set the values and return */
778101b40a0SShannon Nelson 	if (!netif_running(lif->netdev)) {
779101b40a0SShannon Nelson 		lif->nxqs = qparam.nxqs;
780101b40a0SShannon Nelson 
781101b40a0SShannon Nelson 		if (qparam.intr_split) {
782101b40a0SShannon Nelson 			set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
783101b40a0SShannon Nelson 		} else {
784101b40a0SShannon Nelson 			clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
785101b40a0SShannon Nelson 			lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
786101b40a0SShannon Nelson 			lif->tx_coalesce_hw = lif->rx_coalesce_hw;
787101b40a0SShannon Nelson 		}
788101b40a0SShannon Nelson 		return 0;
789101b40a0SShannon Nelson 	}
790101b40a0SShannon Nelson 
79179a58c06SShannon Nelson 	mutex_lock(&lif->queue_lock);
792101b40a0SShannon Nelson 	err = ionic_reconfigure_queues(lif, &qparam);
79379a58c06SShannon Nelson 	mutex_unlock(&lif->queue_lock);
794101b40a0SShannon Nelson 	if (err)
795101b40a0SShannon Nelson 		netdev_info(netdev, "Queue reconfiguration failed, changes canceled: %d\n", err);
796101b40a0SShannon Nelson 
797101b40a0SShannon Nelson 	return err;
7984d03e00aSShannon Nelson }
7994d03e00aSShannon Nelson 
ionic_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * info,u32 * rules)800aa319881SShannon Nelson static int ionic_get_rxnfc(struct net_device *netdev,
801aa319881SShannon Nelson 			   struct ethtool_rxnfc *info, u32 *rules)
802aa319881SShannon Nelson {
803aa319881SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
804aa319881SShannon Nelson 	int err = 0;
805aa319881SShannon Nelson 
806aa319881SShannon Nelson 	switch (info->cmd) {
807aa319881SShannon Nelson 	case ETHTOOL_GRXRINGS:
808aa319881SShannon Nelson 		info->data = lif->nxqs;
809aa319881SShannon Nelson 		break;
810aa319881SShannon Nelson 	default:
8113711d44fSShannon Nelson 		netdev_dbg(netdev, "Command parameter %d is not supported\n",
812aa319881SShannon Nelson 			   info->cmd);
813aa319881SShannon Nelson 		err = -EOPNOTSUPP;
814aa319881SShannon Nelson 	}
815aa319881SShannon Nelson 
816aa319881SShannon Nelson 	return err;
817aa319881SShannon Nelson }
818aa319881SShannon Nelson 
ionic_get_rxfh_indir_size(struct net_device * netdev)819aa319881SShannon Nelson static u32 ionic_get_rxfh_indir_size(struct net_device *netdev)
820aa319881SShannon Nelson {
821aa319881SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
822aa319881SShannon Nelson 
823aa319881SShannon Nelson 	return le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
824aa319881SShannon Nelson }
825aa319881SShannon Nelson 
ionic_get_rxfh_key_size(struct net_device * netdev)826aa319881SShannon Nelson static u32 ionic_get_rxfh_key_size(struct net_device *netdev)
827aa319881SShannon Nelson {
828aa319881SShannon Nelson 	return IONIC_RSS_HASH_KEY_SIZE;
829aa319881SShannon Nelson }
830aa319881SShannon Nelson 
ionic_get_rxfh(struct net_device * netdev,u32 * indir,u8 * key,u8 * hfunc)831aa319881SShannon Nelson static int ionic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
832aa319881SShannon Nelson 			  u8 *hfunc)
833aa319881SShannon Nelson {
834aa319881SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
835aa319881SShannon Nelson 	unsigned int i, tbl_sz;
836aa319881SShannon Nelson 
837aa319881SShannon Nelson 	if (indir) {
838aa319881SShannon Nelson 		tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
839aa319881SShannon Nelson 		for (i = 0; i < tbl_sz; i++)
840aa319881SShannon Nelson 			indir[i] = lif->rss_ind_tbl[i];
841aa319881SShannon Nelson 	}
842aa319881SShannon Nelson 
843aa319881SShannon Nelson 	if (key)
844aa319881SShannon Nelson 		memcpy(key, lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
845aa319881SShannon Nelson 
846aa319881SShannon Nelson 	if (hfunc)
847aa319881SShannon Nelson 		*hfunc = ETH_RSS_HASH_TOP;
848aa319881SShannon Nelson 
849aa319881SShannon Nelson 	return 0;
850aa319881SShannon Nelson }
851aa319881SShannon Nelson 
ionic_set_rxfh(struct net_device * netdev,const u32 * indir,const u8 * key,const u8 hfunc)852aa319881SShannon Nelson static int ionic_set_rxfh(struct net_device *netdev, const u32 *indir,
853aa319881SShannon Nelson 			  const u8 *key, const u8 hfunc)
854aa319881SShannon Nelson {
855aa319881SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
856aa319881SShannon Nelson 
857aa319881SShannon Nelson 	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
858aa319881SShannon Nelson 		return -EOPNOTSUPP;
859aa319881SShannon Nelson 
86010dd7b4fSZheng Yongjun 	return ionic_lif_rss_config(lif, lif->rss_types, key, indir);
861aa319881SShannon Nelson }
862aa319881SShannon Nelson 
ionic_set_tunable(struct net_device * dev,const struct ethtool_tunable * tuna,const void * data)8638c15440bSShannon Nelson static int ionic_set_tunable(struct net_device *dev,
8648c15440bSShannon Nelson 			     const struct ethtool_tunable *tuna,
8658c15440bSShannon Nelson 			     const void *data)
8668c15440bSShannon Nelson {
8678c15440bSShannon Nelson 	struct ionic_lif *lif = netdev_priv(dev);
8688c15440bSShannon Nelson 
8698c15440bSShannon Nelson 	switch (tuna->id) {
8708c15440bSShannon Nelson 	case ETHTOOL_RX_COPYBREAK:
8718c15440bSShannon Nelson 		lif->rx_copybreak = *(u32 *)data;
8728c15440bSShannon Nelson 		break;
8738c15440bSShannon Nelson 	default:
8748c15440bSShannon Nelson 		return -EOPNOTSUPP;
8758c15440bSShannon Nelson 	}
8768c15440bSShannon Nelson 
8778c15440bSShannon Nelson 	return 0;
8788c15440bSShannon Nelson }
8798c15440bSShannon Nelson 
ionic_get_tunable(struct net_device * netdev,const struct ethtool_tunable * tuna,void * data)8808c15440bSShannon Nelson static int ionic_get_tunable(struct net_device *netdev,
8818c15440bSShannon Nelson 			     const struct ethtool_tunable *tuna, void *data)
8828c15440bSShannon Nelson {
8838c15440bSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
8848c15440bSShannon Nelson 
8858c15440bSShannon Nelson 	switch (tuna->id) {
8868c15440bSShannon Nelson 	case ETHTOOL_RX_COPYBREAK:
8878c15440bSShannon Nelson 		*(u32 *)data = lif->rx_copybreak;
8888c15440bSShannon Nelson 		break;
8898c15440bSShannon Nelson 	default:
8908c15440bSShannon Nelson 		return -EOPNOTSUPP;
8918c15440bSShannon Nelson 	}
8928c15440bSShannon Nelson 
8938c15440bSShannon Nelson 	return 0;
8948c15440bSShannon Nelson }
8958c15440bSShannon Nelson 
ionic_get_module_info(struct net_device * netdev,struct ethtool_modinfo * modinfo)8964d03e00aSShannon Nelson static int ionic_get_module_info(struct net_device *netdev,
8974d03e00aSShannon Nelson 				 struct ethtool_modinfo *modinfo)
8984d03e00aSShannon Nelson 
8994d03e00aSShannon Nelson {
9004d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
9014d03e00aSShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
9024d03e00aSShannon Nelson 	struct ionic_xcvr_status *xcvr;
903840eef59SShannon Nelson 	struct sfp_eeprom_base *sfp;
9044d03e00aSShannon Nelson 
9054d03e00aSShannon Nelson 	xcvr = &idev->port_info->status.xcvr;
906840eef59SShannon Nelson 	sfp = (struct sfp_eeprom_base *) xcvr->sprom;
9074d03e00aSShannon Nelson 
9084d03e00aSShannon Nelson 	/* report the module data type and length */
909840eef59SShannon Nelson 	switch (sfp->phys_id) {
910840eef59SShannon Nelson 	case SFF8024_ID_SFP:
9114d03e00aSShannon Nelson 		modinfo->type = ETH_MODULE_SFF_8079;
9124d03e00aSShannon Nelson 		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
9134d03e00aSShannon Nelson 		break;
914840eef59SShannon Nelson 	case SFF8024_ID_QSFP_8436_8636:
915840eef59SShannon Nelson 	case SFF8024_ID_QSFP28_8636:
9164d03e00aSShannon Nelson 		modinfo->type = ETH_MODULE_SFF_8436;
9174d03e00aSShannon Nelson 		modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
9184d03e00aSShannon Nelson 		break;
9194d03e00aSShannon Nelson 	default:
9204d03e00aSShannon Nelson 		netdev_info(netdev, "unknown xcvr type 0x%02x\n",
9214d03e00aSShannon Nelson 			    xcvr->sprom[0]);
922840eef59SShannon Nelson 		modinfo->type = 0;
923840eef59SShannon Nelson 		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
9244d03e00aSShannon Nelson 		break;
9254d03e00aSShannon Nelson 	}
9264d03e00aSShannon Nelson 
9274d03e00aSShannon Nelson 	return 0;
9284d03e00aSShannon Nelson }
9294d03e00aSShannon Nelson 
ionic_get_module_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)9304d03e00aSShannon Nelson static int ionic_get_module_eeprom(struct net_device *netdev,
9314d03e00aSShannon Nelson 				   struct ethtool_eeprom *ee,
9324d03e00aSShannon Nelson 				   u8 *data)
9334d03e00aSShannon Nelson {
9344d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
9354d03e00aSShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
9364d03e00aSShannon Nelson 	struct ionic_xcvr_status *xcvr;
9374d03e00aSShannon Nelson 	char tbuf[sizeof(xcvr->sprom)];
9384d03e00aSShannon Nelson 	int count = 10;
9394d03e00aSShannon Nelson 	u32 len;
9404d03e00aSShannon Nelson 
9414d03e00aSShannon Nelson 	/* The NIC keeps the module prom up-to-date in the DMA space
9424d03e00aSShannon Nelson 	 * so we can simply copy the module bytes into the data buffer.
9434d03e00aSShannon Nelson 	 */
9444d03e00aSShannon Nelson 	xcvr = &idev->port_info->status.xcvr;
9454d03e00aSShannon Nelson 	len = min_t(u32, sizeof(xcvr->sprom), ee->len);
9464d03e00aSShannon Nelson 
9474d03e00aSShannon Nelson 	do {
948*6cd7cad9SShannon Nelson 		memcpy(data, &xcvr->sprom[ee->offset], len);
949*6cd7cad9SShannon Nelson 		memcpy(tbuf, &xcvr->sprom[ee->offset], len);
9504d03e00aSShannon Nelson 
9514d03e00aSShannon Nelson 		/* Let's make sure we got a consistent copy */
9524d03e00aSShannon Nelson 		if (!memcmp(data, tbuf, len))
9534d03e00aSShannon Nelson 			break;
9544d03e00aSShannon Nelson 
9554d03e00aSShannon Nelson 	} while (--count);
9564d03e00aSShannon Nelson 
9574d03e00aSShannon Nelson 	if (!count)
9584d03e00aSShannon Nelson 		return -ETIMEDOUT;
9594d03e00aSShannon Nelson 
9604d03e00aSShannon Nelson 	return 0;
9614d03e00aSShannon Nelson }
9624d03e00aSShannon Nelson 
ionic_get_ts_info(struct net_device * netdev,struct ethtool_ts_info * info)963f8ba81daSShannon Nelson static int ionic_get_ts_info(struct net_device *netdev,
964f8ba81daSShannon Nelson 			     struct ethtool_ts_info *info)
965f8ba81daSShannon Nelson {
966f8ba81daSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
967f8ba81daSShannon Nelson 	struct ionic *ionic = lif->ionic;
968f8ba81daSShannon Nelson 	__le64 mask;
969f8ba81daSShannon Nelson 
970f8ba81daSShannon Nelson 	if (!lif->phc || !lif->phc->ptp)
971f8ba81daSShannon Nelson 		return ethtool_op_get_ts_info(netdev, info);
972f8ba81daSShannon Nelson 
973f8ba81daSShannon Nelson 	info->phc_index = ptp_clock_index(lif->phc->ptp);
974f8ba81daSShannon Nelson 
975f8ba81daSShannon Nelson 	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
976f8ba81daSShannon Nelson 				SOF_TIMESTAMPING_RX_SOFTWARE |
977f8ba81daSShannon Nelson 				SOF_TIMESTAMPING_SOFTWARE |
978f8ba81daSShannon Nelson 				SOF_TIMESTAMPING_TX_HARDWARE |
979f8ba81daSShannon Nelson 				SOF_TIMESTAMPING_RX_HARDWARE |
980f8ba81daSShannon Nelson 				SOF_TIMESTAMPING_RAW_HARDWARE;
981f8ba81daSShannon Nelson 
982f8ba81daSShannon Nelson 	/* tx modes */
983f8ba81daSShannon Nelson 
984f8ba81daSShannon Nelson 	info->tx_types = BIT(HWTSTAMP_TX_OFF) |
985f8ba81daSShannon Nelson 			 BIT(HWTSTAMP_TX_ON);
986f8ba81daSShannon Nelson 
987f8ba81daSShannon Nelson 	mask = cpu_to_le64(BIT_ULL(IONIC_TXSTAMP_ONESTEP_SYNC));
988f8ba81daSShannon Nelson 	if (ionic->ident.lif.eth.hwstamp_tx_modes & mask)
989f8ba81daSShannon Nelson 		info->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_SYNC);
990f8ba81daSShannon Nelson 
991f8ba81daSShannon Nelson 	mask = cpu_to_le64(BIT_ULL(IONIC_TXSTAMP_ONESTEP_P2P));
992f8ba81daSShannon Nelson 	if (ionic->ident.lif.eth.hwstamp_tx_modes & mask)
993f8ba81daSShannon Nelson 		info->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_P2P);
994f8ba81daSShannon Nelson 
995f8ba81daSShannon Nelson 	/* rx filters */
996f8ba81daSShannon Nelson 
997f8ba81daSShannon Nelson 	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
998f8ba81daSShannon Nelson 			   BIT(HWTSTAMP_FILTER_ALL);
999f8ba81daSShannon Nelson 
1000f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_NTP_ALL);
1001f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10021da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_NTP_ALL);
1003f8ba81daSShannon Nelson 
1004f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_SYNC);
1005f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10061da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC);
1007f8ba81daSShannon Nelson 
1008f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_DREQ);
1009f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10101da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ);
1011f8ba81daSShannon Nelson 
1012f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_ALL);
1013f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10141da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT);
1015f8ba81daSShannon Nelson 
1016f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_SYNC);
1017f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10181da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC);
1019f8ba81daSShannon Nelson 
1020f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_DREQ);
1021f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10221da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
1023f8ba81daSShannon Nelson 
1024f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_ALL);
1025f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10261da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
1027f8ba81daSShannon Nelson 
1028f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_SYNC);
1029f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10301da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC);
1031f8ba81daSShannon Nelson 
1032f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_DREQ);
1033f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10341da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ);
1035f8ba81daSShannon Nelson 
1036f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_ALL);
1037f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10381da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
1039f8ba81daSShannon Nelson 
1040f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_SYNC);
1041f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10421da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_SYNC);
1043f8ba81daSShannon Nelson 
1044f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_DREQ);
1045f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10461da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
1047f8ba81daSShannon Nelson 
1048f8ba81daSShannon Nelson 	mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_ALL);
1049f8ba81daSShannon Nelson 	if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask)
10501da41aa1SShannon Nelson 		info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
1051f8ba81daSShannon Nelson 
1052f8ba81daSShannon Nelson 	return 0;
1053f8ba81daSShannon Nelson }
1054f8ba81daSShannon Nelson 
ionic_nway_reset(struct net_device * netdev)10554d03e00aSShannon Nelson static int ionic_nway_reset(struct net_device *netdev)
10564d03e00aSShannon Nelson {
10574d03e00aSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
10584d03e00aSShannon Nelson 	struct ionic *ionic = lif->ionic;
10594d03e00aSShannon Nelson 	int err = 0;
10604d03e00aSShannon Nelson 
1061f5123686SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
1062f5123686SShannon Nelson 		return -EBUSY;
1063f5123686SShannon Nelson 
10644d03e00aSShannon Nelson 	/* flap the link to force auto-negotiation */
10654d03e00aSShannon Nelson 
10664d03e00aSShannon Nelson 	mutex_lock(&ionic->dev_cmd_lock);
10674d03e00aSShannon Nelson 
10684d03e00aSShannon Nelson 	ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_DOWN);
10694d03e00aSShannon Nelson 	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
10704d03e00aSShannon Nelson 
10714d03e00aSShannon Nelson 	if (!err) {
10724d03e00aSShannon Nelson 		ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP);
10734d03e00aSShannon Nelson 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
10744d03e00aSShannon Nelson 	}
10754d03e00aSShannon Nelson 
10764d03e00aSShannon Nelson 	mutex_unlock(&ionic->dev_cmd_lock);
10774d03e00aSShannon Nelson 
10784d03e00aSShannon Nelson 	return err;
10794d03e00aSShannon Nelson }
10804d03e00aSShannon Nelson 
10814d03e00aSShannon Nelson static const struct ethtool_ops ionic_ethtool_ops = {
108204a83459SShannon Nelson 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
108304a83459SShannon Nelson 				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
108404a83459SShannon Nelson 				     ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
108540bc471dSShannon Nelson 	.supported_ring_params = ETHTOOL_RING_USE_TX_PUSH |
108640bc471dSShannon Nelson 				 ETHTOOL_RING_USE_RX_PUSH,
10874d03e00aSShannon Nelson 	.get_drvinfo		= ionic_get_drvinfo,
10884d03e00aSShannon Nelson 	.get_regs_len		= ionic_get_regs_len,
10894d03e00aSShannon Nelson 	.get_regs		= ionic_get_regs,
10904d03e00aSShannon Nelson 	.get_link		= ethtool_op_get_link,
1091132b4ebfSNitya Sunkad 	.get_link_ext_stats	= ionic_get_link_ext_stats,
10924d03e00aSShannon Nelson 	.get_link_ksettings	= ionic_get_link_ksettings,
1093e95f922fSShannon Nelson 	.set_link_ksettings	= ionic_set_link_ksettings,
10944d03e00aSShannon Nelson 	.get_coalesce		= ionic_get_coalesce,
10958c15440bSShannon Nelson 	.set_coalesce		= ionic_set_coalesce,
10964d03e00aSShannon Nelson 	.get_ringparam		= ionic_get_ringparam,
10974d03e00aSShannon Nelson 	.set_ringparam		= ionic_set_ringparam,
10984d03e00aSShannon Nelson 	.get_channels		= ionic_get_channels,
10994d03e00aSShannon Nelson 	.set_channels		= ionic_set_channels,
1100e470355bSShannon Nelson 	.get_strings		= ionic_get_strings,
1101e470355bSShannon Nelson 	.get_ethtool_stats	= ionic_get_stats,
1102e470355bSShannon Nelson 	.get_sset_count		= ionic_get_sset_count,
1103aa319881SShannon Nelson 	.get_rxnfc		= ionic_get_rxnfc,
1104aa319881SShannon Nelson 	.get_rxfh_indir_size	= ionic_get_rxfh_indir_size,
1105aa319881SShannon Nelson 	.get_rxfh_key_size	= ionic_get_rxfh_key_size,
1106aa319881SShannon Nelson 	.get_rxfh		= ionic_get_rxfh,
1107aa319881SShannon Nelson 	.set_rxfh		= ionic_set_rxfh,
11088c15440bSShannon Nelson 	.get_tunable		= ionic_get_tunable,
11098c15440bSShannon Nelson 	.set_tunable		= ionic_set_tunable,
11104d03e00aSShannon Nelson 	.get_module_info	= ionic_get_module_info,
11114d03e00aSShannon Nelson 	.get_module_eeprom	= ionic_get_module_eeprom,
11124d03e00aSShannon Nelson 	.get_pauseparam		= ionic_get_pauseparam,
11134d03e00aSShannon Nelson 	.set_pauseparam		= ionic_set_pauseparam,
1114e95f922fSShannon Nelson 	.get_fecparam		= ionic_get_fecparam,
1115e95f922fSShannon Nelson 	.set_fecparam		= ionic_set_fecparam,
1116f8ba81daSShannon Nelson 	.get_ts_info		= ionic_get_ts_info,
11174d03e00aSShannon Nelson 	.nway_reset		= ionic_nway_reset,
11184d03e00aSShannon Nelson };
11194d03e00aSShannon Nelson 
ionic_ethtool_set_ops(struct net_device * netdev)11204d03e00aSShannon Nelson void ionic_ethtool_set_ops(struct net_device *netdev)
11214d03e00aSShannon Nelson {
11224d03e00aSShannon Nelson 	netdev->ethtool_ops = &ionic_ethtool_ops;
11234d03e00aSShannon Nelson }
1124