Skip to content

Commit

Permalink
net: phy: genphy_loopback: add link speed configuration
Browse files Browse the repository at this point in the history
In case of loopback, in most cases we need to disable autoneg support
and force some speed configuration. Otherwise, depending on currently
active auto negotiated link speed, the loopback may or may not work.

This patch was tested with following PHYs: TJA1102, KSZ8081, KSZ9031,
AT8035, AR9331.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Oleksij Rempel authored and David S. Miller committed Apr 20, 2021
1 parent f4f86d8 commit 014068d
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 3 deletions.
3 changes: 2 additions & 1 deletion drivers/net/phy/phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ int phy_start_cable_test_tdr(struct phy_device *phydev,
}
EXPORT_SYMBOL(phy_start_cable_test_tdr);

static int phy_config_aneg(struct phy_device *phydev)
int phy_config_aneg(struct phy_device *phydev)
{
if (phydev->drv->config_aneg)
return phydev->drv->config_aneg(phydev);
Expand All @@ -714,6 +714,7 @@ static int phy_config_aneg(struct phy_device *phydev)

return genphy_config_aneg(phydev);
}
EXPORT_SYMBOL(phy_config_aneg);

/**
* phy_check_link_status - check link status and set state accordingly
Expand Down
28 changes: 26 additions & 2 deletions drivers/net/phy/phy_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -2565,8 +2565,32 @@ EXPORT_SYMBOL(genphy_resume);

int genphy_loopback(struct phy_device *phydev, bool enable)
{
return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
enable ? BMCR_LOOPBACK : 0);
if (enable) {
u16 val, ctl = BMCR_LOOPBACK;
int ret;

if (phydev->speed == SPEED_1000)
ctl |= BMCR_SPEED1000;
else if (phydev->speed == SPEED_100)
ctl |= BMCR_SPEED100;

if (phydev->duplex == DUPLEX_FULL)
ctl |= BMCR_FULLDPLX;

phy_modify(phydev, MII_BMCR, ~0, ctl);

ret = phy_read_poll_timeout(phydev, MII_BMSR, val,
val & BMSR_LSTATUS,
5000, 500000, true);
if (ret)
return ret;
} else {
phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);

phy_config_aneg(phydev);
}

return 0;
}
EXPORT_SYMBOL(genphy_loopback);

Expand Down
1 change: 1 addition & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,7 @@ void phy_disconnect(struct phy_device *phydev);
void phy_detach(struct phy_device *phydev);
void phy_start(struct phy_device *phydev);
void phy_stop(struct phy_device *phydev);
int phy_config_aneg(struct phy_device *phydev);
int phy_start_aneg(struct phy_device *phydev);
int phy_aneg_done(struct phy_device *phydev);
int phy_speed_down(struct phy_device *phydev, bool sync);
Expand Down

0 comments on commit 014068d

Please sign in to comment.