diff options
Diffstat (limited to 'drivers/net/phy/marvell.c')
-rw-r--r-- | drivers/net/phy/marvell.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 623292948fa7..c248c90510ae 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1902,6 +1902,43 @@ error: return err; } +/* m88e1510_resume + * + * The 88e1510 PHY has an erratum where the phy downshift counter is not cleared + * after phy being suspended(BMCR_PDOWN set) and then later resumed(BMCR_PDOWN + * cleared). This can cause the link to intermittently downshift to a lower speed. + * + * Disabling and re-enabling the downshift feature clears the counter, allowing + * the PHY to retry gigabit link negotiation up to the programmed retry count + * before downshifting. This behavior has been observed on copper links. + */ +static int m88e1510_resume(struct phy_device *phydev) +{ + int err; + u8 cnt = 0; + + err = marvell_resume(phydev); + if (err < 0) + return err; + + /* read downshift counter value */ + err = m88e1011_get_downshift(phydev, &cnt); + if (err < 0) + return err; + + if (cnt) { + /* downshift disabled */ + err = m88e1011_set_downshift(phydev, 0); + if (err < 0) + return err; + + /* downshift enabled, with previous counter value */ + err = m88e1011_set_downshift(phydev, cnt); + } + + return err; +} + static int marvell_aneg_done(struct phy_device *phydev) { int retval = phy_read(phydev, MII_M1011_PHY_STATUS); @@ -3563,20 +3600,18 @@ static int marvell_probe(struct phy_device *phydev) static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) { - DECLARE_PHY_INTERFACE_MASK(interfaces); struct phy_device *phydev = upstream; + const struct sfp_module_caps *caps; phy_interface_t interface; struct device *dev; int oldpage; int ret = 0; u16 mode; - __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; - dev = &phydev->mdio.dev; - sfp_parse_support(phydev->sfp_bus, id, supported, interfaces); - interface = sfp_select_interface(phydev->sfp_bus, supported); + caps = sfp_get_module_caps(phydev->sfp_bus); + interface = sfp_select_interface(phydev->sfp_bus, caps->link_modes); dev_info(dev, "%s SFP module inserted\n", phy_modes(interface)); @@ -3923,7 +3958,7 @@ static struct phy_driver marvell_drivers[] = { .handle_interrupt = marvell_handle_interrupt, .get_wol = m88e1318_get_wol, .set_wol = m88e1318_set_wol, - .resume = marvell_resume, + .resume = m88e1510_resume, .suspend = marvell_suspend, .read_page = marvell_read_page, .write_page = marvell_write_page, |