diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 95f0419ba21..88237bdb525 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -713,60 +713,57 @@ static void phy_timer(unsigned long data) break; case PHY_AN: + err = phy_read_status(phydev); + + if (err < 0) + break; + + /* If the link is down, give up on + * negotiation for now */ + if (!phydev->link) { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + break; + } + /* Check if negotiation is done. Break * if there's an error */ err = phy_aneg_done(phydev); if (err < 0) break; - /* If auto-negotiation is done, we change to - * either RUNNING, or NOLINK */ + /* If AN is done, we're running */ if (err > 0) { - err = phy_read_status(phydev); - - if (err) - break; - - if (phydev->link) { - phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - } else { - phydev->state = PHY_NOLINK; - netif_carrier_off(phydev->attached_dev); - } - + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); phydev->adjust_link(phydev->attached_dev); } else if (0 == phydev->link_timeout--) { - /* The counter expired, so either we - * switch to forced mode, or the - * magic_aneg bit exists, and we try aneg - * again */ - if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) { - int idx; - - /* We'll start from the - * fastest speed, and work - * our way down */ - idx = phy_find_valid(0, - phydev->supported); - - phydev->speed = settings[idx].speed; - phydev->duplex = settings[idx].duplex; - - phydev->autoneg = AUTONEG_DISABLE; - phydev->state = PHY_FORCING; - phydev->link_timeout = - PHY_FORCE_TIMEOUT; - - pr_info("Trying %d/%s\n", - phydev->speed, - DUPLEX_FULL == - phydev->duplex ? - "FULL" : "HALF"); - } + int idx; needs_aneg = 1; + /* If we have the magic_aneg bit, + * we try again */ + if (phydev->drv->flags & PHY_HAS_MAGICANEG) + break; + + /* The timer expired, and we still + * don't have a setting, so we try + * forcing it until we find one that + * works, starting from the fastest speed, + * and working our way down */ + idx = phy_find_valid(0, phydev->supported); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; + + phydev->autoneg = AUTONEG_DISABLE; + + pr_info("Trying %d/%s\n", phydev->speed, + DUPLEX_FULL == + phydev->duplex ? + "FULL" : "HALF"); } break; case PHY_NOLINK: @@ -782,7 +779,7 @@ static void phy_timer(unsigned long data) } break; case PHY_FORCING: - err = phy_read_status(phydev); + err = genphy_update_link(phydev); if (err) break; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3bbd5e70c20..2a08b2b62c4 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -427,6 +427,7 @@ int genphy_update_link(struct phy_device *phydev) return 0; } +EXPORT_SYMBOL(genphy_update_link); /* genphy_read_status *