sfc: commonise ethtool link handling functions
Link speeds, FEC, and autonegotiation are all things EF100 will share. Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9043f48fd3
commit
bdccfd2d4e
@ -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 |
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user