marvell_read_status() no longer first switches to the fiber page, instead looks at the already active register page first. In case the link is down, switches to the other (fiber/copper) register page.
Unneeded register page switching of the Marvell 88E1510 PHY can cause the ethernet driver to register a link down & up event. Signed-off-by: Frank de Brabander <debraban...@gmail.com> --- drivers/net/phy/marvell.c | 59 ++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index abb7876..31de2db 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -194,6 +194,11 @@ static int marvell_read_page(struct phy_device *phydev) return __phy_read(phydev, MII_MARVELL_PHY_PAGE); } +static int marvell_get_page(struct phy_device *phydev) +{ + return phy_read(phydev, MII_MARVELL_PHY_PAGE); +} + static int marvell_write_page(struct phy_device *phydev, int page) { return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); @@ -1245,47 +1250,59 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) * Some Marvell's phys have two modes: fiber and copper. * Both need status checked. * Description: - * First, check the fiber link and status. - * If the fiber link is down, check the copper link and status which - * will be the default value if both link are down. + * First, check the link of the currently selected page. Unneeded page + * switches should be prevented, they can trigger the ethernet driver to + * register a link down event. + * If the first checked link type is down, continue with checking the other + * link type. This is needed for platforms that have a fiber and copper link + * connected to the same phy. */ static int marvell_read_status(struct phy_device *phydev) { int err; + int page; - /* Check the fiber mode first */ if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported) && phydev->interface != PHY_INTERFACE_MODE_SGMII) { - err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); - if (err < 0) - goto error; + page = marvell_get_page(phydev); + if (page < 0) + return page; + + if (page != MII_MARVELL_FIBER_PAGE && + page != MII_MARVELL_COPPER_PAGE) { + page = MII_MARVELL_FIBER_PAGE; - err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); + err = marvell_set_page(phydev, page); + if (err < 0) + return err; + } + + err = marvell_read_status_page(phydev, page); if (err < 0) - goto error; + return err; - /* If the fiber link is up, it is the selected and - * used link. In this case, we need to stay in the - * fiber page. Please to be careful about that, avoid - * to restore Copper page in other functions which - * could break the behaviour for some fiber phy like + /* If the link is up, it is the selected and + * used link. In this case, we need to stay in that + * page. Please to be careful about that, avoid + * to restore the page in other functions which + * could break the behaviour for some phy's like * 88E1512. */ if (phydev->link) return 0; - /* If fiber link is down, check and save copper mode state */ - err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + page = (page == MII_MARVELL_FIBER_PAGE) ? + MII_MARVELL_COPPER_PAGE : MII_MARVELL_FIBER_PAGE; + + err = marvell_set_page(phydev, page); if (err < 0) - goto error; + return err; + + return marvell_read_status_page(phydev, page); } return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); - -error: - marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); - return err; } /* marvell_suspend -- 2.7.4