Skip to content

Commit 014068d

Browse files
oleremdavem330
authored andcommitted
net: phy: genphy_loopback: add link speed configuration
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>
1 parent f4f86d8 commit 014068d

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

drivers/net/phy/phy.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ int phy_start_cable_test_tdr(struct phy_device *phydev,
701701
}
702702
EXPORT_SYMBOL(phy_start_cable_test_tdr);
703703

704-
static int phy_config_aneg(struct phy_device *phydev)
704+
int phy_config_aneg(struct phy_device *phydev)
705705
{
706706
if (phydev->drv->config_aneg)
707707
return phydev->drv->config_aneg(phydev);
@@ -714,6 +714,7 @@ static int phy_config_aneg(struct phy_device *phydev)
714714

715715
return genphy_config_aneg(phydev);
716716
}
717+
EXPORT_SYMBOL(phy_config_aneg);
717718

718719
/**
719720
* phy_check_link_status - check link status and set state accordingly

drivers/net/phy/phy_device.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,8 +2565,32 @@ EXPORT_SYMBOL(genphy_resume);
25652565

25662566
int genphy_loopback(struct phy_device *phydev, bool enable)
25672567
{
2568-
return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
2569-
enable ? BMCR_LOOPBACK : 0);
2568+
if (enable) {
2569+
u16 val, ctl = BMCR_LOOPBACK;
2570+
int ret;
2571+
2572+
if (phydev->speed == SPEED_1000)
2573+
ctl |= BMCR_SPEED1000;
2574+
else if (phydev->speed == SPEED_100)
2575+
ctl |= BMCR_SPEED100;
2576+
2577+
if (phydev->duplex == DUPLEX_FULL)
2578+
ctl |= BMCR_FULLDPLX;
2579+
2580+
phy_modify(phydev, MII_BMCR, ~0, ctl);
2581+
2582+
ret = phy_read_poll_timeout(phydev, MII_BMSR, val,
2583+
val & BMSR_LSTATUS,
2584+
5000, 500000, true);
2585+
if (ret)
2586+
return ret;
2587+
} else {
2588+
phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);
2589+
2590+
phy_config_aneg(phydev);
2591+
}
2592+
2593+
return 0;
25702594
}
25712595
EXPORT_SYMBOL(genphy_loopback);
25722596

include/linux/phy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,7 @@ void phy_disconnect(struct phy_device *phydev);
14101410
void phy_detach(struct phy_device *phydev);
14111411
void phy_start(struct phy_device *phydev);
14121412
void phy_stop(struct phy_device *phydev);
1413+
int phy_config_aneg(struct phy_device *phydev);
14131414
int phy_start_aneg(struct phy_device *phydev);
14141415
int phy_aneg_done(struct phy_device *phydev);
14151416
int phy_speed_down(struct phy_device *phydev, bool sync);

0 commit comments

Comments
 (0)