ionic: implement ethtool set-fec

Wire up the --set-fec and --show-fec features in the ethtool
callbacks and pull the related code out of set_link_ksettings.

Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Shannon Nelson 2019-09-30 20:03:25 -07:00 committed by David S. Miller
parent 780eded34c
commit e95f922f4c

View file

@ -254,12 +254,9 @@ static int ionic_set_link_ksettings(struct net_device *netdev,
struct ionic_lif *lif = netdev_priv(netdev);
struct ionic *ionic = lif->ionic;
struct ionic_dev *idev;
u32 req_rs, req_fc;
u8 fec_type;
int err = 0;
idev = &lif->ionic->idev;
fec_type = IONIC_PORT_FEC_TYPE_NONE;
/* set autoneg */
if (ks->base.autoneg != idev->port_info->config.an_enable) {
@ -281,29 +278,6 @@ static int ionic_set_link_ksettings(struct net_device *netdev,
return err;
}
/* set FEC */
req_rs = ethtool_link_ksettings_test_link_mode(ks, advertising, FEC_RS);
req_fc = ethtool_link_ksettings_test_link_mode(ks, advertising, FEC_BASER);
if (req_rs && req_fc) {
netdev_info(netdev, "Only select one FEC mode at a time\n");
return -EINVAL;
} else if (req_fc) {
fec_type = IONIC_PORT_FEC_TYPE_FC;
} else if (req_rs) {
fec_type = IONIC_PORT_FEC_TYPE_RS;
} else if (!(req_rs | req_fc)) {
fec_type = IONIC_PORT_FEC_TYPE_NONE;
}
if (fec_type != idev->port_info->config.fec_type) {
mutex_lock(&ionic->dev_cmd_lock);
ionic_dev_cmd_port_fec(idev, fec_type);
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
mutex_unlock(&ionic->dev_cmd_lock);
if (err)
return err;
}
return 0;
}
@ -353,6 +327,70 @@ static int ionic_set_pauseparam(struct net_device *netdev,
return 0;
}
static int ionic_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
struct ionic_lif *lif = netdev_priv(netdev);
switch (lif->ionic->idev.port_info->config.fec_type) {
case IONIC_PORT_FEC_TYPE_NONE:
fec->active_fec = ETHTOOL_FEC_OFF;
break;
case IONIC_PORT_FEC_TYPE_RS:
fec->active_fec = ETHTOOL_FEC_RS;
break;
case IONIC_PORT_FEC_TYPE_FC:
fec->active_fec = ETHTOOL_FEC_BASER;
break;
}
fec->fec = ETHTOOL_FEC_OFF | ETHTOOL_FEC_RS | ETHTOOL_FEC_BASER;
return 0;
}
static int ionic_set_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
struct ionic_lif *lif = netdev_priv(netdev);
u8 fec_type;
int ret = 0;
if (lif->ionic->idev.port_info->config.an_enable) {
netdev_err(netdev, "FEC request not allowed while autoneg is enabled\n");
return -EINVAL;
}
switch (fec->fec) {
case ETHTOOL_FEC_NONE:
fec_type = IONIC_PORT_FEC_TYPE_NONE;
break;
case ETHTOOL_FEC_OFF:
fec_type = IONIC_PORT_FEC_TYPE_NONE;
break;
case ETHTOOL_FEC_RS:
fec_type = IONIC_PORT_FEC_TYPE_RS;
break;
case ETHTOOL_FEC_BASER:
fec_type = IONIC_PORT_FEC_TYPE_FC;
break;
case ETHTOOL_FEC_AUTO:
default:
netdev_err(netdev, "FEC request 0x%04x not supported\n",
fec->fec);
return -EINVAL;
}
if (fec_type != lif->ionic->idev.port_info->config.fec_type) {
mutex_lock(&lif->ionic->dev_cmd_lock);
ionic_dev_cmd_port_fec(&lif->ionic->idev, fec_type);
ret = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
mutex_unlock(&lif->ionic->dev_cmd_lock);
}
return ret;
}
static int ionic_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *coalesce)
{
@ -751,6 +789,7 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_regs = ionic_get_regs,
.get_link = ethtool_op_get_link,
.get_link_ksettings = ionic_get_link_ksettings,
.set_link_ksettings = ionic_set_link_ksettings,
.get_coalesce = ionic_get_coalesce,
.set_coalesce = ionic_set_coalesce,
.get_ringparam = ionic_get_ringparam,
@ -773,7 +812,8 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_module_eeprom = ionic_get_module_eeprom,
.get_pauseparam = ionic_get_pauseparam,
.set_pauseparam = ionic_set_pauseparam,
.set_link_ksettings = ionic_set_link_ksettings,
.get_fecparam = ionic_get_fecparam,
.set_fecparam = ionic_set_fecparam,
.nway_reset = ionic_nway_reset,
};