summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c3
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_netdev.h4
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_phylink.c61
3 files changed, 68 insertions, 0 deletions
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index 4646e80c34624..7cb191155d795 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -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,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
index c30c060b72e0e..943a52c77ed32 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
@@ -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_ */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index a693a9f4d5fde..3a11d2a27de95 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -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)
{