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

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
...@@ -1654,3 +1654,151 @@ int liquidio_get_speed(struct lio *lio) ...@@ -1654,3 +1654,151 @@ int liquidio_get_speed(struct lio *lio)
return retval; 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;
}
...@@ -244,6 +244,7 @@ static int lio_get_link_ksettings(struct net_device *netdev, ...@@ -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_XLAUI ||
linfo->link.s.if_mode == INTERFACE_MODE_XFI) { linfo->link.s.if_mode == INTERFACE_MODE_XFI) {
dev_dbg(&oct->pci_dev->dev, "ecmd->base.transceiver is XCVR_EXTERNAL\n"); dev_dbg(&oct->pci_dev->dev, "ecmd->base.transceiver is XCVR_EXTERNAL\n");
ecmd->base.transceiver = XCVR_EXTERNAL;
} else { } else {
dev_err(&oct->pci_dev->dev, "Unknown link interface mode: %d\n", dev_err(&oct->pci_dev->dev, "Unknown link interface mode: %d\n",
linfo->link.s.if_mode); linfo->link.s.if_mode);
...@@ -277,10 +278,12 @@ static int lio_get_link_ksettings(struct net_device *netdev, ...@@ -277,10 +278,12 @@ static int lio_get_link_ksettings(struct net_device *netdev,
10000baseCR_Full); 10000baseCR_Full);
} }
if (oct->no_speed_setting == 0) if (oct->no_speed_setting == 0) {
liquidio_get_speed(lio); liquidio_get_speed(lio);
else liquidio_get_fec(lio);
} else {
oct->speed_setting = 25; oct->speed_setting = 25;
}
if (oct->speed_setting == 10) { if (oct->speed_setting == 10) {
ethtool_link_ksettings_add_link_mode ethtool_link_ksettings_add_link_mode
...@@ -304,6 +307,24 @@ static int lio_get_link_ksettings(struct net_device *netdev, ...@@ -304,6 +307,24 @@ static int lio_get_link_ksettings(struct net_device *netdev,
(ecmd, advertising, (ecmd, advertising,
25000baseCR_Full); 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 */ } else { /* VF */
if (linfo->link.s.speed == 10000) { if (linfo->link.s.speed == 10000) {
ethtool_link_ksettings_add_link_mode ethtool_link_ksettings_add_link_mode
...@@ -3029,9 +3050,60 @@ static int lio_set_priv_flags(struct net_device *netdev, u32 flags) ...@@ -3029,9 +3050,60 @@ static int lio_set_priv_flags(struct net_device *netdev, u32 flags)
return 0; 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 = { static const struct ethtool_ops lio_ethtool_ops = {
.get_link_ksettings = lio_get_link_ksettings, .get_link_ksettings = lio_get_link_ksettings,
.set_link_ksettings = lio_set_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_link = ethtool_op_get_link,
.get_drvinfo = lio_get_drvinfo, .get_drvinfo = lio_get_drvinfo,
.get_ringparam = lio_ethtool_get_ringparam, .get_ringparam = lio_ethtool_get_ringparam,
......
...@@ -3761,6 +3761,14 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) ...@@ -3761,6 +3761,14 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
octeon_dev->speed_setting = 10; octeon_dev->speed_setting = 10;
} }
octeon_dev->speed_boot = octeon_dev->speed_setting; 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, devlink = devlink_alloc(&liquidio_devlink_ops,
......
...@@ -260,6 +260,11 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, ...@@ -260,6 +260,11 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry,
#define OCTNET_CMD_FAIL 0x1 #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_SET 0x2
#define SEAPI_CMD_SPEED_GET 0x3 #define SEAPI_CMD_SPEED_GET 0x3
......
...@@ -316,6 +316,8 @@ struct octdev_props { ...@@ -316,6 +316,8 @@ struct octdev_props {
* device pointer (used for OS specific calls). * device pointer (used for OS specific calls).
*/ */
int rx_on; int rx_on;
int fec;
int fec_boot;
int napi_enabled; int napi_enabled;
int gmxport; int gmxport;
struct net_device *netdev; struct net_device *netdev;
......
...@@ -84,7 +84,10 @@ struct oct_nic_stats_ctrl { ...@@ -84,7 +84,10 @@ struct oct_nic_stats_ctrl {
struct oct_nic_seapi_resp { struct oct_nic_seapi_resp {
u64 rh; u64 rh;
u32 speed; union {
u32 fec_setting;
u32 speed;
};
u64 status; u64 status;
}; };
...@@ -236,6 +239,8 @@ int lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_qs); ...@@ -236,6 +239,8 @@ int lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_qs);
int liquidio_get_speed(struct lio *lio); int liquidio_get_speed(struct lio *lio);
int liquidio_set_speed(struct lio *lio, int speed); int liquidio_set_speed(struct lio *lio, int speed);
int liquidio_get_fec(struct lio *lio);
int liquidio_set_fec(struct lio *lio, int on_off);
/** /**
* \brief Net device change_mtu * \brief Net device change_mtu
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment