Commit 0d087093 authored by Dirk van der Merwe's avatar Dirk van der Merwe Committed by David S. Miller

nfp: implement ethtool FEC mode settings

Add support in the driver ethtool ops to modify the NFP FEC modes.

The FEC modes can be set for vNIC associated with physical ports or
for MAC representor netdevs.
Signed-off-by: default avatarDirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b471232e
...@@ -244,6 +244,30 @@ nfp_app_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) ...@@ -244,6 +244,30 @@ nfp_app_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
nfp_get_drvinfo(app, app->pdev, "*", drvinfo); nfp_get_drvinfo(app, app->pdev, "*", drvinfo);
} }
static void
nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port,
struct ethtool_link_ksettings *c)
{
unsigned int modes;
ethtool_link_ksettings_add_link_mode(c, supported, FEC_NONE);
if (!nfp_eth_can_support_fec(eth_port)) {
ethtool_link_ksettings_add_link_mode(c, advertising, FEC_NONE);
return;
}
modes = nfp_eth_supported_fec_modes(eth_port);
if (modes & NFP_FEC_BASER) {
ethtool_link_ksettings_add_link_mode(c, supported, FEC_BASER);
ethtool_link_ksettings_add_link_mode(c, advertising, FEC_BASER);
}
if (modes & NFP_FEC_REED_SOLOMON) {
ethtool_link_ksettings_add_link_mode(c, supported, FEC_RS);
ethtool_link_ksettings_add_link_mode(c, advertising, FEC_RS);
}
}
/** /**
* nfp_net_get_link_ksettings - Get Link Speed settings * nfp_net_get_link_ksettings - Get Link Speed settings
* @netdev: network interface device structure * @netdev: network interface device structure
...@@ -278,9 +302,11 @@ nfp_net_get_link_ksettings(struct net_device *netdev, ...@@ -278,9 +302,11 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
port = nfp_port_from_netdev(netdev); port = nfp_port_from_netdev(netdev);
eth_port = nfp_port_get_eth_port(port); eth_port = nfp_port_get_eth_port(port);
if (eth_port) if (eth_port) {
cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ? cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ?
AUTONEG_ENABLE : AUTONEG_DISABLE; AUTONEG_ENABLE : AUTONEG_DISABLE;
nfp_net_set_fec_link_mode(eth_port, cmd);
}
if (!netif_carrier_ok(netdev)) if (!netif_carrier_ok(netdev))
return 0; return 0;
...@@ -686,6 +712,91 @@ static int nfp_port_get_sset_count(struct net_device *netdev, int sset) ...@@ -686,6 +712,91 @@ static int nfp_port_get_sset_count(struct net_device *netdev, int sset)
} }
} }
static int nfp_port_fec_ethtool_to_nsp(u32 fec)
{
switch (fec) {
case ETHTOOL_FEC_AUTO:
return NFP_FEC_AUTO_BIT;
case ETHTOOL_FEC_OFF:
return NFP_FEC_DISABLED_BIT;
case ETHTOOL_FEC_RS:
return NFP_FEC_REED_SOLOMON_BIT;
case ETHTOOL_FEC_BASER:
return NFP_FEC_BASER_BIT;
default:
/* NSP only supports a single mode at a time */
return -EOPNOTSUPP;
}
}
static u32 nfp_port_fec_nsp_to_ethtool(u32 fec)
{
u32 result = 0;
if (fec & NFP_FEC_AUTO)
result |= ETHTOOL_FEC_AUTO;
if (fec & NFP_FEC_BASER)
result |= ETHTOOL_FEC_BASER;
if (fec & NFP_FEC_REED_SOLOMON)
result |= ETHTOOL_FEC_RS;
if (fec & NFP_FEC_DISABLED)
result |= ETHTOOL_FEC_OFF;
return result ?: ETHTOOL_FEC_NONE;
}
static int
nfp_port_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *param)
{
struct nfp_eth_table_port *eth_port;
struct nfp_port *port;
param->active_fec = ETHTOOL_FEC_NONE_BIT;
param->fec = ETHTOOL_FEC_NONE_BIT;
port = nfp_port_from_netdev(netdev);
eth_port = nfp_port_get_eth_port(port);
if (!eth_port)
return -EOPNOTSUPP;
if (!nfp_eth_can_support_fec(eth_port))
return 0;
param->fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec_modes_supported);
param->active_fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec);
return 0;
}
static int
nfp_port_set_fecparam(struct net_device *netdev,
struct ethtool_fecparam *param)
{
struct nfp_eth_table_port *eth_port;
struct nfp_port *port;
int err, fec;
port = nfp_port_from_netdev(netdev);
eth_port = nfp_port_get_eth_port(port);
if (!eth_port)
return -EOPNOTSUPP;
if (!nfp_eth_can_support_fec(eth_port))
return -EOPNOTSUPP;
fec = nfp_port_fec_ethtool_to_nsp(param->fec);
if (fec < 0)
return fec;
err = nfp_eth_set_fec(port->app->cpp, eth_port->index, fec);
if (!err)
/* Only refresh if we did something */
nfp_net_refresh_port_table(port);
return err < 0 ? err : 0;
}
/* RX network flow classification (RSS, filters, etc) /* RX network flow classification (RSS, filters, etc)
*/ */
static u32 ethtool_flow_to_nfp_flag(u32 flow_type) static u32 ethtool_flow_to_nfp_flag(u32 flow_type)
...@@ -1144,6 +1255,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { ...@@ -1144,6 +1255,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
.set_channels = nfp_net_set_channels, .set_channels = nfp_net_set_channels,
.get_link_ksettings = nfp_net_get_link_ksettings, .get_link_ksettings = nfp_net_get_link_ksettings,
.set_link_ksettings = nfp_net_set_link_ksettings, .set_link_ksettings = nfp_net_set_link_ksettings,
.get_fecparam = nfp_port_get_fecparam,
.set_fecparam = nfp_port_set_fecparam,
}; };
const struct ethtool_ops nfp_port_ethtool_ops = { const struct ethtool_ops nfp_port_ethtool_ops = {
...@@ -1157,6 +1270,8 @@ const struct ethtool_ops nfp_port_ethtool_ops = { ...@@ -1157,6 +1270,8 @@ const struct ethtool_ops nfp_port_ethtool_ops = {
.get_dump_data = nfp_app_get_dump_data, .get_dump_data = nfp_app_get_dump_data,
.get_link_ksettings = nfp_net_get_link_ksettings, .get_link_ksettings = nfp_net_get_link_ksettings,
.set_link_ksettings = nfp_net_set_link_ksettings, .set_link_ksettings = nfp_net_set_link_ksettings,
.get_fecparam = nfp_port_get_fecparam,
.set_fecparam = nfp_port_set_fecparam,
}; };
void nfp_net_set_ethtool_ops(struct net_device *netdev) void nfp_net_set_ethtool_ops(struct net_device *netdev)
......
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