Commit 75b2c206 authored by Weilin Chang's avatar Weilin Chang Committed by David S. Miller
Browse files

liquidio: Add the features to show FEC settings and set FEC settings



1. Add functions for get_fecparam and set_fecparam.
2. Modify lio_get_link_ksettings to display FEC setting.

Signed-off-by: default avatarWeilin Chang <weilin.chang@cavium.com>
Acked-by: default avatarDerek Chickles <derek.chickles@cavium.com>
Signed-off-by: default avatarFelix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a4ebec03
Loading
Loading
Loading
Loading
+148 −0
Original line number Diff line number Diff line
@@ -1654,3 +1654,151 @@ int liquidio_get_speed(struct lio *lio)

	return retval;
}

int liquidio_set_fec(struct lio *lio, int on_off)
{
	struct oct_nic_seapi_resp *resp;
	struct octeon_soft_command *sc;
	struct octeon_device *oct;
	union octnet_cmd *ncmd;
	int retval;
	u32 var;

	oct = lio->oct_dev;

	if (oct->props[lio->ifidx].fec == on_off)
		return 0;

	if (!OCTEON_CN23XX_PF(oct)) {
		dev_err(&oct->pci_dev->dev, "%s: SET FEC only for PF\n",
			__func__);
		return -1;
	}

	if (oct->speed_boot != 25)  {
		dev_err(&oct->pci_dev->dev,
			"Set FEC only when link speed is 25G during insmod\n");
		return -1;
	}

	sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
				       sizeof(struct oct_nic_seapi_resp), 0);

	ncmd = sc->virtdptr;
	resp = sc->virtrptr;
	memset(resp, 0, sizeof(struct oct_nic_seapi_resp));

	init_completion(&sc->complete);
	sc->sc_status = OCTEON_REQUEST_PENDING;

	ncmd->u64 = 0;
	ncmd->s.cmd = SEAPI_CMD_FEC_SET;
	ncmd->s.param1 = on_off;
	/* SEAPI_CMD_FEC_DISABLE(0) or SEAPI_CMD_FEC_RS(1) */

	octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3));

	sc->iq_no = lio->linfo.txpciq[0].s.q_no;

	octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
				    OPCODE_NIC_UBOOT_CTL, 0, 0, 0);

	retval = octeon_send_soft_command(oct, sc);
	if (retval == IQ_SEND_FAILED) {
		dev_info(&oct->pci_dev->dev, "Failed to send soft command\n");
		octeon_free_soft_command(oct, sc);
		return -EIO;
	}

	retval = wait_for_sc_completion_timeout(oct, sc, 0);
	if (retval)
		return (-EIO);

	var = be32_to_cpu(resp->fec_setting);
	resp->fec_setting = var;
	if (var != on_off) {
		dev_err(&oct->pci_dev->dev,
			"Setting failed fec= %x, expect %x\n",
			var, on_off);
		oct->props[lio->ifidx].fec = var;
		if (resp->fec_setting == SEAPI_CMD_FEC_SET_RS)
			oct->props[lio->ifidx].fec = 1;
		else
			oct->props[lio->ifidx].fec = 0;
	}

	WRITE_ONCE(sc->caller_is_done, true);

	if (oct->props[lio->ifidx].fec !=
	    oct->props[lio->ifidx].fec_boot) {
		dev_dbg(&oct->pci_dev->dev,
			"Reloade driver to chang fec to %s\n",
			oct->props[lio->ifidx].fec ? "on" : "off");
	}

	return retval;
}

int liquidio_get_fec(struct lio *lio)
{
	struct oct_nic_seapi_resp *resp;
	struct octeon_soft_command *sc;
	struct octeon_device *oct;
	union octnet_cmd *ncmd;
	int retval;
	u32 var;

	oct = lio->oct_dev;

	sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
				       sizeof(struct oct_nic_seapi_resp), 0);
	if (!sc)
		return -ENOMEM;

	ncmd = sc->virtdptr;
	resp = sc->virtrptr;
	memset(resp, 0, sizeof(struct oct_nic_seapi_resp));

	init_completion(&sc->complete);
	sc->sc_status = OCTEON_REQUEST_PENDING;

	ncmd->u64 = 0;
	ncmd->s.cmd = SEAPI_CMD_FEC_GET;

	octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3));

	sc->iq_no = lio->linfo.txpciq[0].s.q_no;

	octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
				    OPCODE_NIC_UBOOT_CTL, 0, 0, 0);

	retval = octeon_send_soft_command(oct, sc);
	if (retval == IQ_SEND_FAILED) {
		dev_info(&oct->pci_dev->dev,
			 "%s: Failed to send soft command\n", __func__);
		octeon_free_soft_command(oct, sc);
		return -EIO;
	}

	retval = wait_for_sc_completion_timeout(oct, sc, 0);
	if (retval)
		return retval;

	var = be32_to_cpu(resp->fec_setting);
	resp->fec_setting = var;
	if (resp->fec_setting == SEAPI_CMD_FEC_SET_RS)
		oct->props[lio->ifidx].fec = 1;
	else
		oct->props[lio->ifidx].fec = 0;

	WRITE_ONCE(sc->caller_is_done, true);

	if (oct->props[lio->ifidx].fec !=
	    oct->props[lio->ifidx].fec_boot) {
		dev_dbg(&oct->pci_dev->dev,
			"Reloade driver to chang fec to %s\n",
			oct->props[lio->ifidx].fec ? "on" : "off");
	}

	return retval;
}
+74 −2
Original line number Diff line number Diff line
@@ -244,6 +244,7 @@ static int lio_get_link_ksettings(struct net_device *netdev,
		    linfo->link.s.if_mode == INTERFACE_MODE_XLAUI ||
		    linfo->link.s.if_mode == INTERFACE_MODE_XFI) {
			dev_dbg(&oct->pci_dev->dev, "ecmd->base.transceiver is XCVR_EXTERNAL\n");
			ecmd->base.transceiver = XCVR_EXTERNAL;
		} else {
			dev_err(&oct->pci_dev->dev, "Unknown link interface mode: %d\n",
				linfo->link.s.if_mode);
@@ -277,10 +278,12 @@ static int lio_get_link_ksettings(struct net_device *netdev,
						 10000baseCR_Full);
				}

				if (oct->no_speed_setting == 0)
				if (oct->no_speed_setting == 0) {
					liquidio_get_speed(lio);
				else
					liquidio_get_fec(lio);
				} else {
					oct->speed_setting = 25;
				}

				if (oct->speed_setting == 10) {
					ethtool_link_ksettings_add_link_mode
@@ -304,6 +307,24 @@ static int lio_get_link_ksettings(struct net_device *netdev,
						(ecmd, advertising,
						 25000baseCR_Full);
				}

				if (oct->no_speed_setting)
					break;

				ethtool_link_ksettings_add_link_mode
					(ecmd, supported, FEC_RS);
				ethtool_link_ksettings_add_link_mode
					(ecmd, supported, FEC_NONE);
					/*FEC_OFF*/
				if (oct->props[lio->ifidx].fec == 1) {
					/* ETHTOOL_FEC_RS */
					ethtool_link_ksettings_add_link_mode
						(ecmd, advertising, FEC_RS);
				} else {
					/* ETHTOOL_FEC_OFF */
					ethtool_link_ksettings_add_link_mode
						(ecmd, advertising, FEC_NONE);
				}
			} else { /* VF */
				if (linfo->link.s.speed == 10000) {
					ethtool_link_ksettings_add_link_mode
@@ -3029,9 +3050,60 @@ static int lio_set_priv_flags(struct net_device *netdev, u32 flags)
	return 0;
}

static int lio_get_fecparam(struct net_device *netdev,
			    struct ethtool_fecparam *fec)
{
	struct lio *lio = GET_LIO(netdev);
	struct octeon_device *oct = lio->oct_dev;

	fec->active_fec = ETHTOOL_FEC_NONE;
	fec->fec = ETHTOOL_FEC_NONE;

	if (oct->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID ||
	    oct->subsystem_id == OCTEON_CN2360_25GB_SUBSYS_ID) {
		if (oct->no_speed_setting == 1)
			return 0;

		liquidio_get_fec(lio);
		fec->fec = (ETHTOOL_FEC_RS | ETHTOOL_FEC_OFF);
		if (oct->props[lio->ifidx].fec == 1)
			fec->active_fec = ETHTOOL_FEC_RS;
		else
			fec->active_fec = ETHTOOL_FEC_OFF;
	}

	return 0;
}

static int lio_set_fecparam(struct net_device *netdev,
			    struct ethtool_fecparam *fec)
{
	struct lio *lio = GET_LIO(netdev);
	struct octeon_device *oct = lio->oct_dev;

	if (oct->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID ||
	    oct->subsystem_id == OCTEON_CN2360_25GB_SUBSYS_ID) {
		if (oct->no_speed_setting == 1)
			return -EOPNOTSUPP;

		if (fec->fec & ETHTOOL_FEC_OFF)
			liquidio_set_fec(lio, 0);
		else if (fec->fec & ETHTOOL_FEC_RS)
			liquidio_set_fec(lio, 1);
		else
			return -EOPNOTSUPP;
	} else {
		return -EOPNOTSUPP;
	}

	return 0;
}

static const struct ethtool_ops lio_ethtool_ops = {
	.get_link_ksettings	= lio_get_link_ksettings,
	.set_link_ksettings	= lio_set_link_ksettings,
	.get_fecparam		= lio_get_fecparam,
	.set_fecparam		= lio_set_fecparam,
	.get_link		= ethtool_op_get_link,
	.get_drvinfo		= lio_get_drvinfo,
	.get_ringparam		= lio_ethtool_get_ringparam,
+8 −0
Original line number Diff line number Diff line
@@ -3761,6 +3761,14 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
			octeon_dev->speed_setting = 10;
		}
		octeon_dev->speed_boot = octeon_dev->speed_setting;

		/* don't read FEC setting if unsupported by f/w (see above) */
		if (octeon_dev->speed_boot == 25 &&
		    !octeon_dev->no_speed_setting) {
			liquidio_get_fec(lio);
			octeon_dev->props[lio->ifidx].fec_boot =
				octeon_dev->props[lio->ifidx].fec;
		}
	}

	devlink = devlink_alloc(&liquidio_devlink_ops,
+5 −0
Original line number Diff line number Diff line
@@ -260,6 +260,11 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry,

#define   OCTNET_CMD_FAIL 0x1

#define   SEAPI_CMD_FEC_SET             0x0
#define   SEAPI_CMD_FEC_SET_DISABLE       0x0
#define   SEAPI_CMD_FEC_SET_RS            0x1
#define   SEAPI_CMD_FEC_GET             0x1

#define   SEAPI_CMD_SPEED_SET           0x2
#define   SEAPI_CMD_SPEED_GET           0x3

+2 −0
Original line number Diff line number Diff line
@@ -316,6 +316,8 @@ struct octdev_props {
	 * device pointer (used for OS specific calls).
	 */
	int    rx_on;
	int    fec;
	int    fec_boot;
	int    napi_enabled;
	int    gmxport;
	struct net_device *netdev;
Loading