|
@@ -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,
|
|
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+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 = {
|
|
.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 = {
|
|
.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)
|