]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fbnic: Add support for reporting link config
authorAlexander Duyck <alexanderduyck@fb.com>
Wed, 18 Jun 2025 22:08:02 +0000 (15:08 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 24 Jun 2025 07:31:46 +0000 (09:31 +0200)
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>
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
drivers/net/ethernet/meta/fbnic/fbnic_phylink.c

index 4646e80c34624ab55dca85dd70c977a6d250ffe3..7cb191155d795eb3a730e9eb86332b836b9221b7 100644 (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,
index c30c060b72e0e655c9dd792b565cbce9a54bebe2..943a52c77ed324e700d0f7feaa527e554fba83ef 100644 (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_ */
index a693a9f4d5fde6bed500485afbaf548b6428e094..3a11d2a27de958d56077f690547ac439f2357352 100644 (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)
 {