Merge tag 'omap-for-v5.6/fixes-rc7-signed' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / drivers / net / phy / phy_device.c
index 28e3c5c..ac27841 100644 (file)
@@ -1059,18 +1059,12 @@ EXPORT_SYMBOL(phy_disconnect);
 static int phy_poll_reset(struct phy_device *phydev)
 {
        /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
-       unsigned int retries = 12;
-       int ret;
-
-       do {
-               msleep(50);
-               ret = phy_read(phydev, MII_BMCR);
-               if (ret < 0)
-                       return ret;
-       } while (ret & BMCR_RESET && --retries);
-       if (ret & BMCR_RESET)
-               return -ETIMEDOUT;
+       int ret, val;
 
+       ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
+                                   50000, 600000, true);
+       if (ret)
+               return ret;
        /* Some chips (smsc911x) may still need up to another 1ms after the
         * BMCR_RESET bit is cleared before they are usable.
         */
@@ -1525,23 +1519,22 @@ EXPORT_SYMBOL(phy_detach);
 
 int phy_suspend(struct phy_device *phydev)
 {
-       struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
-       struct net_device *netdev = phydev->attached_dev;
        struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
-       int ret = 0;
+       struct net_device *netdev = phydev->attached_dev;
+       struct phy_driver *phydrv = phydev->drv;
+       int ret;
 
        /* If the device has WOL enabled, we cannot suspend the PHY */
        phy_ethtool_get_wol(phydev, &wol);
        if (wol.wolopts || (netdev && netdev->wol_enabled))
                return -EBUSY;
 
-       if (phydev->drv && phydrv->suspend)
-               ret = phydrv->suspend(phydev);
-
-       if (ret)
-               return ret;
+       if (!phydrv || !phydrv->suspend)
+               return 0;
 
-       phydev->suspended = true;
+       ret = phydrv->suspend(phydev);
+       if (!ret)
+               phydev->suspended = true;
 
        return ret;
 }
@@ -1549,18 +1542,17 @@ EXPORT_SYMBOL(phy_suspend);
 
 int __phy_resume(struct phy_device *phydev)
 {
-       struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
-       int ret = 0;
+       struct phy_driver *phydrv = phydev->drv;
+       int ret;
 
        WARN_ON(!mutex_is_locked(&phydev->lock));
 
-       if (phydev->drv && phydrv->resume)
-               ret = phydrv->resume(phydev);
-
-       if (ret)
-               return ret;
+       if (!phydrv || !phydrv->resume)
+               return 0;
 
-       phydev->suspended = false;
+       ret = phydrv->resume(phydev);
+       if (!ret)
+               phydev->suspended = false;
 
        return ret;
 }
@@ -1935,9 +1927,10 @@ int genphy_update_link(struct phy_device *phydev)
 
        /* The link state is latched low so that momentary link
         * drops can be detected. Do not double-read the status
-        * in polling mode to detect such short link drops.
+        * in polling mode to detect such short link drops except
+        * the link was already down.
         */
-       if (!phy_polling_mode(phydev)) {
+       if (!phy_polling_mode(phydev) || !phydev->link) {
                status = phy_read(phydev, MII_BMSR);
                if (status < 0)
                        return status;
@@ -2366,22 +2359,7 @@ void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx)
        __ETHTOOL_DECLARE_LINK_MODE_MASK(oldadv);
 
        linkmode_copy(oldadv, phydev->advertising);
-
-       linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
-                          phydev->advertising);
-       linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
-                          phydev->advertising);
-
-       if (rx) {
-               linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
-                                phydev->advertising);
-               linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
-                                phydev->advertising);
-       }
-
-       if (tx)
-               linkmode_change_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
-                                   phydev->advertising);
+       linkmode_set_pause(phydev->advertising, tx, rx);
 
        if (!linkmode_equal(oldadv, phydev->advertising) &&
            phydev->autoneg)
@@ -2414,6 +2392,32 @@ bool phy_validate_pause(struct phy_device *phydev,
 }
 EXPORT_SYMBOL(phy_validate_pause);
 
+/**
+ * phy_get_pause - resolve negotiated pause modes
+ * @phydev: phy_device struct
+ * @tx_pause: pointer to bool to indicate whether transmit pause should be
+ * enabled.
+ * @rx_pause: pointer to bool to indicate whether receive pause should be
+ * enabled.
+ *
+ * Resolve and return the flow control modes according to the negotiation
+ * result. This includes checking that we are operating in full duplex mode.
+ * See linkmode_resolve_pause() for further details.
+ */
+void phy_get_pause(struct phy_device *phydev, bool *tx_pause, bool *rx_pause)
+{
+       if (phydev->duplex != DUPLEX_FULL) {
+               *tx_pause = false;
+               *rx_pause = false;
+               return;
+       }
+
+       return linkmode_resolve_pause(phydev->advertising,
+                                     phydev->lp_advertising,
+                                     tx_pause, rx_pause);
+}
+EXPORT_SYMBOL(phy_get_pause);
+
 static bool phy_drv_supports_irq(struct phy_driver *phydrv)
 {
        return phydrv->config_intr && phydrv->ack_interrupt;
@@ -2571,6 +2575,7 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
        new_driver->mdiodrv.driver.probe = phy_probe;
        new_driver->mdiodrv.driver.remove = phy_remove;
        new_driver->mdiodrv.driver.owner = owner;
+       new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
 
        retval = driver_register(&new_driver->mdiodrv.driver);
        if (retval) {