From bdccfd2d4ea7a0676045b16e83a1138deff20923 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Mon, 29 Jun 2020 14:34:50 +0100 Subject: sfc: commonise ethtool link handling functions Link speeds, FEC, and autonegotiation are all things EF100 will share. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ethtool.c | 148 ------------------------------ drivers/net/ethernet/sfc/ethtool_common.c | 146 +++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/ethtool_common.h | 12 ++- 3 files changed, 157 insertions(+), 149 deletions(-) diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 04e88d05e8ff..55413d451ac3 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -54,58 +54,6 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, return 0; } -/* This must be called with rtnl_lock held. */ -static int -efx_ethtool_get_link_ksettings(struct net_device *net_dev, - struct ethtool_link_ksettings *cmd) -{ - struct efx_nic *efx = netdev_priv(net_dev); - struct efx_link_state *link_state = &efx->link_state; - u32 supported; - - mutex_lock(&efx->mac_lock); - efx->phy_op->get_link_ksettings(efx, cmd); - mutex_unlock(&efx->mac_lock); - - /* Both MACs support pause frames (bidirectional and respond-only) */ - ethtool_convert_link_mode_to_legacy_u32(&supported, - cmd->link_modes.supported); - - supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - - ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, - supported); - - if (LOOPBACK_INTERNAL(efx)) { - cmd->base.speed = link_state->speed; - cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; - } - - return 0; -} - -/* This must be called with rtnl_lock held. */ -static int -efx_ethtool_set_link_ksettings(struct net_device *net_dev, - const struct ethtool_link_ksettings *cmd) -{ - struct efx_nic *efx = netdev_priv(net_dev); - int rc; - - /* GMAC does not support 1000Mbps HD */ - if ((cmd->base.speed == SPEED_1000) && - (cmd->base.duplex != DUPLEX_FULL)) { - netif_dbg(efx, drv, efx->net_dev, - "rejecting unsupported 1000Mbps HD setting\n"); - return -EINVAL; - } - - mutex_lock(&efx->mac_lock); - rc = efx->phy_op->set_link_ksettings(efx, cmd); - mutex_unlock(&efx->mac_lock); - return rc; -} - static int efx_ethtool_get_regs_len(struct net_device *net_dev) { return efx_nic_get_regs_len(netdev_priv(net_dev)); @@ -168,14 +116,6 @@ fail: test->flags |= ETH_TEST_FL_FAILED; } -/* Restart autonegotiation */ -static int efx_ethtool_nway_reset(struct net_device *net_dev) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - return mdio45_nway_restart(&efx->mdio); -} - /* * Each channel has a single IRQ and moderation timer, started by any * completion (or other event). Unless the module parameter @@ -300,64 +240,6 @@ static int efx_ethtool_set_ringparam(struct net_device *net_dev, return efx_realloc_channels(efx, ring->rx_pending, txq_entries); } -static int efx_ethtool_set_pauseparam(struct net_device *net_dev, - struct ethtool_pauseparam *pause) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u8 wanted_fc, old_fc; - u32 old_adv; - int rc = 0; - - mutex_lock(&efx->mac_lock); - - wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | - (pause->tx_pause ? EFX_FC_TX : 0) | - (pause->autoneg ? EFX_FC_AUTO : 0)); - - if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { - netif_dbg(efx, drv, efx->net_dev, - "Flow control unsupported: tx ON rx OFF\n"); - rc = -EINVAL; - goto out; - } - - if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising[0]) { - netif_dbg(efx, drv, efx->net_dev, - "Autonegotiation is disabled\n"); - rc = -EINVAL; - goto out; - } - - /* Hook for Falcon bug 11482 workaround */ - if (efx->type->prepare_enable_fc_tx && - (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX)) - efx->type->prepare_enable_fc_tx(efx); - - old_adv = efx->link_advertising[0]; - old_fc = efx->wanted_fc; - efx_link_set_wanted_fc(efx, wanted_fc); - if (efx->link_advertising[0] != old_adv || - (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { - rc = efx->phy_op->reconfigure(efx); - if (rc) { - netif_err(efx, drv, efx->net_dev, - "Unable to advertise requested flow " - "control setting\n"); - goto out; - } - } - - /* Reconfigure the MAC. The PHY *may* generate a link state change event - * if the user just changed the advertised capabilities, but there's no - * harm doing this twice */ - efx_mac_reconfigure(efx); - -out: - mutex_unlock(&efx->mac_lock); - - return rc; -} - static void efx_ethtool_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) { @@ -1104,36 +986,6 @@ static int efx_ethtool_get_module_info(struct net_device *net_dev, return ret; } -static int efx_ethtool_get_fecparam(struct net_device *net_dev, - struct ethtool_fecparam *fecparam) -{ - struct efx_nic *efx = netdev_priv(net_dev); - int rc; - - if (!efx->phy_op || !efx->phy_op->get_fecparam) - return -EOPNOTSUPP; - mutex_lock(&efx->mac_lock); - rc = efx->phy_op->get_fecparam(efx, fecparam); - mutex_unlock(&efx->mac_lock); - - return rc; -} - -static int efx_ethtool_set_fecparam(struct net_device *net_dev, - struct ethtool_fecparam *fecparam) -{ - struct efx_nic *efx = netdev_priv(net_dev); - int rc; - - if (!efx->phy_op || !efx->phy_op->get_fecparam) - return -EOPNOTSUPP; - mutex_lock(&efx->mac_lock); - rc = efx->phy_op->set_fecparam(efx, fecparam); - mutex_unlock(&efx->mac_lock); - - return rc; -} - const struct ethtool_ops efx_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_USECS_IRQ | diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c index b8d281ab6c7a..b91961126eeb 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.c +++ b/drivers/net/ethernet/sfc/ethtool_common.c @@ -124,6 +124,14 @@ void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable) efx->msg_enable = msg_enable; } +/* Restart autonegotiation */ +int efx_ethtool_nway_reset(struct net_device *net_dev) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + return mdio45_nway_restart(&efx->mdio); +} + void efx_ethtool_get_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { @@ -134,6 +142,64 @@ void efx_ethtool_get_pauseparam(struct net_device *net_dev, pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); } +int efx_ethtool_set_pauseparam(struct net_device *net_dev, + struct ethtool_pauseparam *pause) +{ + struct efx_nic *efx = netdev_priv(net_dev); + u8 wanted_fc, old_fc; + u32 old_adv; + int rc = 0; + + mutex_lock(&efx->mac_lock); + + wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | + (pause->tx_pause ? EFX_FC_TX : 0) | + (pause->autoneg ? EFX_FC_AUTO : 0)); + + if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { + netif_dbg(efx, drv, efx->net_dev, + "Flow control unsupported: tx ON rx OFF\n"); + rc = -EINVAL; + goto out; + } + + if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising[0]) { + netif_dbg(efx, drv, efx->net_dev, + "Autonegotiation is disabled\n"); + rc = -EINVAL; + goto out; + } + + /* Hook for Falcon bug 11482 workaround */ + if (efx->type->prepare_enable_fc_tx && + (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX)) + efx->type->prepare_enable_fc_tx(efx); + + old_adv = efx->link_advertising[0]; + old_fc = efx->wanted_fc; + efx_link_set_wanted_fc(efx, wanted_fc); + if (efx->link_advertising[0] != old_adv || + (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { + rc = efx->phy_op->reconfigure(efx); + if (rc) { + netif_err(efx, drv, efx->net_dev, + "Unable to advertise requested flow " + "control setting\n"); + goto out; + } + } + + /* Reconfigure the MAC. The PHY *may* generate a link state change event + * if the user just changed the advertised capabilities, but there's no + * harm doing this twice */ + efx_mac_reconfigure(efx); + +out: + mutex_unlock(&efx->mac_lock); + + return rc; +} + /** * efx_fill_test - fill in an individual self-test entry * @test_index: Index of the test @@ -455,3 +521,83 @@ void efx_ethtool_get_stats(struct net_device *net_dev, efx_ptp_update_stats(efx, data); } + +/* This must be called with rtnl_lock held. */ +int efx_ethtool_get_link_ksettings(struct net_device *net_dev, + struct ethtool_link_ksettings *cmd) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_link_state *link_state = &efx->link_state; + u32 supported; + + mutex_lock(&efx->mac_lock); + efx->phy_op->get_link_ksettings(efx, cmd); + mutex_unlock(&efx->mac_lock); + + /* Both MACs support pause frames (bidirectional and respond-only) */ + ethtool_convert_link_mode_to_legacy_u32(&supported, + cmd->link_modes.supported); + + supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + + if (LOOPBACK_INTERNAL(efx)) { + cmd->base.speed = link_state->speed; + cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; + } + + return 0; +} + +/* This must be called with rtnl_lock held. */ +int efx_ethtool_set_link_ksettings(struct net_device *net_dev, + const struct ethtool_link_ksettings *cmd) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int rc; + + /* GMAC does not support 1000Mbps HD */ + if ((cmd->base.speed == SPEED_1000) && + (cmd->base.duplex != DUPLEX_FULL)) { + netif_dbg(efx, drv, efx->net_dev, + "rejecting unsupported 1000Mbps HD setting\n"); + return -EINVAL; + } + + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->set_link_ksettings(efx, cmd); + mutex_unlock(&efx->mac_lock); + return rc; +} + +int efx_ethtool_get_fecparam(struct net_device *net_dev, + struct ethtool_fecparam *fecparam) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int rc; + + if (!efx->phy_op || !efx->phy_op->get_fecparam) + return -EOPNOTSUPP; + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->get_fecparam(efx, fecparam); + mutex_unlock(&efx->mac_lock); + + return rc; +} + +int efx_ethtool_set_fecparam(struct net_device *net_dev, + struct ethtool_fecparam *fecparam) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int rc; + + if (!efx->phy_op || !efx->phy_op->get_fecparam) + return -EOPNOTSUPP; + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->set_fecparam(efx, fecparam); + mutex_unlock(&efx->mac_lock); + + return rc; +} diff --git a/drivers/net/ethernet/sfc/ethtool_common.h b/drivers/net/ethernet/sfc/ethtool_common.h index fa624313f330..eaa1fd9157f8 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.h +++ b/drivers/net/ethernet/sfc/ethtool_common.h @@ -15,8 +15,11 @@ void efx_ethtool_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info); u32 efx_ethtool_get_msglevel(struct net_device *net_dev); void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable); +int efx_ethtool_nway_reset(struct net_device *net_dev); void efx_ethtool_get_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause); +int efx_ethtool_set_pauseparam(struct net_device *net_dev, + struct ethtool_pauseparam *pause); int efx_ethtool_fill_self_tests(struct efx_nic *efx, struct efx_self_tests *tests, u8 *strings, u64 *data); @@ -26,5 +29,12 @@ void efx_ethtool_get_strings(struct net_device *net_dev, u32 string_set, void efx_ethtool_get_stats(struct net_device *net_dev, struct ethtool_stats *stats __attribute__ ((unused)), u64 *data); - +int efx_ethtool_get_link_ksettings(struct net_device *net_dev, + struct ethtool_link_ksettings *out); +int efx_ethtool_set_link_ksettings(struct net_device *net_dev, + const struct ethtool_link_ksettings *settings); +int efx_ethtool_get_fecparam(struct net_device *net_dev, + struct ethtool_fecparam *fecparam); +int efx_ethtool_set_fecparam(struct net_device *net_dev, + struct ethtool_fecparam *fecparam); #endif -- cgit v1.2.3