fbnic: Add support for reporting link config

This change adds some basic support for reporting the current link config
to the user via ethtool. Currently the main components reported are the
carrier status, link speed, and FEC.

For now we are handling the FEC directly as phylink doesn't have support
for it. The plan is to work on incorporating FEC support into phylink and
eventually adding the ability for us to set the FEC configuration through
phylink itself.

In addition as we don't yet have SFP or PHY support the listed modes
supported are including ones not supported by the media we are attached to.
That will hopefully be addressed once we can get the QSFP modules
supported.

Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
Link: https://patch.msgid.link/175028448275.625704.60592644122010798.stgit@ahduyck-xeon-server.home.arpa
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Alexander Duyck 2025-06-18 15:08:02 -07:00 committed by Paolo Abeni
parent 22780f69fb
commit fb9a3bb7f7
3 changed files with 68 additions and 0 deletions

View File

@ -1683,6 +1683,7 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
.get_drvinfo = fbnic_get_drvinfo,
.get_regs_len = fbnic_get_regs_len,
.get_regs = fbnic_get_regs,
.get_link = ethtool_op_get_link,
.get_coalesce = fbnic_get_coalesce,
.set_coalesce = fbnic_set_coalesce,
.get_ringparam = fbnic_get_ringparam,
@ -1705,6 +1706,8 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
.set_channels = fbnic_set_channels,
.get_ts_info = fbnic_get_ts_info,
.get_ts_stats = fbnic_get_ts_stats,
.get_link_ksettings = fbnic_phylink_ethtool_ksettings_get,
.get_fecparam = fbnic_phylink_get_fecparam,
.get_eth_mac_stats = fbnic_get_eth_mac_stats,
.get_eth_ctrl_stats = fbnic_get_eth_ctrl_stats,
.get_rmon_stats = fbnic_get_rmon_stats,

View File

@ -92,5 +92,9 @@ void fbnic_time_stop(struct fbnic_net *fbn);
void __fbnic_set_rx_mode(struct net_device *netdev);
void fbnic_clear_rx_mode(struct net_device *netdev);
int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev,
struct ethtool_link_ksettings *cmd);
int fbnic_phylink_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fecparam);
int fbnic_phylink_init(struct net_device *netdev);
#endif /* _FBNIC_NETDEV_H_ */

View File

@ -24,6 +24,67 @@ static phy_interface_t fbnic_phylink_select_interface(u8 aui)
return PHY_INTERFACE_MODE_NA;
}
static void
fbnic_phylink_get_supported_fec_modes(unsigned long *supported)
{
/* The NIC can support up to 8 possible combinations.
* Either 50G-CR, or 100G-CR2
* This is with RS FEC mode only
* Either 25G-CR, or 50G-CR2
* This is with No FEC, RS, or Base-R
*/
if (phylink_test(supported, 100000baseCR2_Full) ||
phylink_test(supported, 50000baseCR_Full))
phylink_set(supported, FEC_RS);
if (phylink_test(supported, 50000baseCR2_Full) ||
phylink_test(supported, 25000baseCR_Full)) {
phylink_set(supported, FEC_BASER);
phylink_set(supported, FEC_NONE);
phylink_set(supported, FEC_RS);
}
}
int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
struct fbnic_net *fbn = netdev_priv(netdev);
int err;
err = phylink_ethtool_ksettings_get(fbn->phylink, cmd);
if (!err) {
unsigned long *supp = cmd->link_modes.supported;
cmd->base.port = PORT_DA;
cmd->lanes = (fbn->aui & FBNIC_AUI_MODE_R2) ? 2 : 1;
fbnic_phylink_get_supported_fec_modes(supp);
}
return err;
}
int fbnic_phylink_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fecparam)
{
struct fbnic_net *fbn = netdev_priv(netdev);
if (fbn->fec & FBNIC_FEC_RS) {
fecparam->active_fec = ETHTOOL_FEC_RS;
fecparam->fec = ETHTOOL_FEC_RS;
} else if (fbn->fec & FBNIC_FEC_BASER) {
fecparam->active_fec = ETHTOOL_FEC_BASER;
fecparam->fec = ETHTOOL_FEC_BASER;
} else {
fecparam->active_fec = ETHTOOL_FEC_OFF;
fecparam->fec = ETHTOOL_FEC_OFF;
}
if (fbn->aui & FBNIC_AUI_MODE_PAM4)
fecparam->fec |= ETHTOOL_FEC_AUTO;
return 0;
}
static struct fbnic_net *
fbnic_pcs_to_net(struct phylink_pcs *pcs)
{