net: mdio: add mdio45_ethtool_ksettings_get

There is a function in mdio for the old ethtool api gset.
We add a new function mdio45_ethtool_ksettings_get for the
new ethtool api glinksettings.

Signed-off-by: Philippe Reynes <tremyfr@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Philippe Reynes 2017-01-01 19:02:45 +01:00 committed by David S. Miller
parent 525dfa2cdc
commit 8e4881aa1d
2 changed files with 199 additions and 0 deletions

View File

@ -341,6 +341,184 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
}
EXPORT_SYMBOL(mdio45_ethtool_gset_npage);
/**
* mdio45_ethtool_ksettings_get_npage - get settings for ETHTOOL_GLINKSETTINGS
* @mdio: MDIO interface
* @cmd: Ethtool request structure
* @npage_adv: Modes currently advertised on next pages
* @npage_lpa: Modes advertised by link partner on next pages
*
* The @cmd parameter is expected to have been cleared before calling
* mdio45_ethtool_ksettings_get_npage().
*
* Since the CSRs for auto-negotiation using next pages are not fully
* standardised, this function does not attempt to decode them. The
* caller must pass them in.
*/
void mdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio,
struct ethtool_link_ksettings *cmd,
u32 npage_adv, u32 npage_lpa)
{
int reg;
u32 speed, supported = 0, advertising = 0, lp_advertising = 0;
BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22);
BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45);
cmd->base.phy_address = mdio->prtad;
cmd->base.mdio_support =
mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22);
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_CTRL2);
switch (reg & MDIO_PMA_CTRL2_TYPE) {
case MDIO_PMA_CTRL2_10GBT:
case MDIO_PMA_CTRL2_1000BT:
case MDIO_PMA_CTRL2_100BTX:
case MDIO_PMA_CTRL2_10BT:
cmd->base.port = PORT_TP;
supported = SUPPORTED_TP;
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_SPEED);
if (reg & MDIO_SPEED_10G)
supported |= SUPPORTED_10000baseT_Full;
if (reg & MDIO_PMA_SPEED_1000)
supported |= (SUPPORTED_1000baseT_Full |
SUPPORTED_1000baseT_Half);
if (reg & MDIO_PMA_SPEED_100)
supported |= (SUPPORTED_100baseT_Full |
SUPPORTED_100baseT_Half);
if (reg & MDIO_PMA_SPEED_10)
supported |= (SUPPORTED_10baseT_Full |
SUPPORTED_10baseT_Half);
advertising = ADVERTISED_TP;
break;
case MDIO_PMA_CTRL2_10GBCX4:
cmd->base.port = PORT_OTHER;
supported = 0;
advertising = 0;
break;
case MDIO_PMA_CTRL2_10GBKX4:
case MDIO_PMA_CTRL2_10GBKR:
case MDIO_PMA_CTRL2_1000BKX:
cmd->base.port = PORT_OTHER;
supported = SUPPORTED_Backplane;
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_PMA_EXTABLE);
if (reg & MDIO_PMA_EXTABLE_10GBKX4)
supported |= SUPPORTED_10000baseKX4_Full;
if (reg & MDIO_PMA_EXTABLE_10GBKR)
supported |= SUPPORTED_10000baseKR_Full;
if (reg & MDIO_PMA_EXTABLE_1000BKX)
supported |= SUPPORTED_1000baseKX_Full;
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_PMA_10GBR_FECABLE);
if (reg & MDIO_PMA_10GBR_FECABLE_ABLE)
supported |= SUPPORTED_10000baseR_FEC;
advertising = ADVERTISED_Backplane;
break;
/* All the other defined modes are flavours of optical */
default:
cmd->base.port = PORT_FIBRE;
supported = SUPPORTED_FIBRE;
advertising = ADVERTISED_FIBRE;
break;
}
if (mdio->mmds & MDIO_DEVS_AN) {
supported |= SUPPORTED_Autoneg;
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
MDIO_CTRL1);
if (reg & MDIO_AN_CTRL1_ENABLE) {
cmd->base.autoneg = AUTONEG_ENABLE;
advertising |=
ADVERTISED_Autoneg |
mdio45_get_an(mdio, MDIO_AN_ADVERTISE) |
npage_adv;
} else {
cmd->base.autoneg = AUTONEG_DISABLE;
}
} else {
cmd->base.autoneg = AUTONEG_DISABLE;
}
if (cmd->base.autoneg) {
u32 modes = 0;
int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad,
MDIO_MMD_AN, MDIO_STAT1);
/* If AN is complete and successful, report best common
* mode, otherwise report best advertised mode.
*/
if (an_stat & MDIO_AN_STAT1_COMPLETE) {
lp_advertising =
mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa;
if (an_stat & MDIO_AN_STAT1_LPABLE)
lp_advertising |= ADVERTISED_Autoneg;
modes = advertising & lp_advertising;
}
if ((modes & ~ADVERTISED_Autoneg) == 0)
modes = advertising;
if (modes & (ADVERTISED_10000baseT_Full |
ADVERTISED_10000baseKX4_Full |
ADVERTISED_10000baseKR_Full)) {
speed = SPEED_10000;
cmd->base.duplex = DUPLEX_FULL;
} else if (modes & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseKX_Full)) {
speed = SPEED_1000;
cmd->base.duplex = !(modes & ADVERTISED_1000baseT_Half);
} else if (modes & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
speed = SPEED_100;
cmd->base.duplex = !!(modes & ADVERTISED_100baseT_Full);
} else {
speed = SPEED_10;
cmd->base.duplex = !!(modes & ADVERTISED_10baseT_Full);
}
} else {
/* Report forced settings */
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_CTRL1);
speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1)
* ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10));
cmd->base.duplex = (reg & MDIO_CTRL1_FULLDPLX ||
speed == SPEED_10000);
}
cmd->base.speed = speed;
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
supported);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
advertising);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
lp_advertising);
/* 10GBASE-T MDI/MDI-X */
if (cmd->base.port == PORT_TP && (cmd->base.speed == SPEED_10000)) {
switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_PMA_10GBT_SWAPPOL)) {
case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
cmd->base.eth_tp_mdix = ETH_TP_MDI;
break;
case 0:
cmd->base.eth_tp_mdix = ETH_TP_MDI_X;
break;
default:
/* It's complicated... */
cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
break;
}
}
}
EXPORT_SYMBOL(mdio45_ethtool_ksettings_get_npage);
/**
* mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs
* @mdio: MDIO interface

View File

@ -130,6 +130,10 @@ extern int mdio45_nway_restart(const struct mdio_if_info *mdio);
extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
struct ethtool_cmd *ecmd,
u32 npage_adv, u32 npage_lpa);
extern void
mdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio,
struct ethtool_link_ksettings *cmd,
u32 npage_adv, u32 npage_lpa);
/**
* mdio45_ethtool_gset - get settings for ETHTOOL_GSET
@ -147,6 +151,23 @@ static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio,
mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0);
}
/**
* mdio45_ethtool_ksettings_get - get settings for ETHTOOL_GLINKSETTINGS
* @mdio: MDIO interface
* @cmd: Ethtool request structure
*
* Since the CSRs for auto-negotiation using next pages are not fully
* standardised, this function does not attempt to decode them. Use
* mdio45_ethtool_ksettings_get_npage() to specify advertisement bits
* from next pages.
*/
static inline void
mdio45_ethtool_ksettings_get(const struct mdio_if_info *mdio,
struct ethtool_link_ksettings *cmd)
{
mdio45_ethtool_ksettings_get_npage(mdio, cmd, 0, 0);
}
extern int mdio_mii_ioctl(const struct mdio_if_info *mdio,
struct mii_ioctl_data *mii_data, int cmd);